彻底改版2.0
BIN
netfriend/0snap/astackwidget.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
netfriend/0snap/imagecropper.jpg
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
netfriend/0snap/imageviewwindow.jpg
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
netfriend/0snap/sliderpuzzlewidget.jpg
Normal file
|
After Width: | Height: | Size: 29 KiB |
172
netfriend/astackwidget/astackwidget.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
#include "astackwidget.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QPropertyAnimation>
|
||||
|
||||
AStackWidget::AStackWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_offset = 0;
|
||||
m_curIndex = 0;
|
||||
m_lastIndex = 0;
|
||||
m_duration = 500;
|
||||
m_moveAnimation = new QPropertyAnimation(this, "");
|
||||
m_moveAnimation->setDuration(m_duration);
|
||||
connect(m_moveAnimation, &QPropertyAnimation::valueChanged, this, &AStackWidget::onValueChanged);
|
||||
connect(m_moveAnimation, &QPropertyAnimation::finished, this, &AStackWidget::onMoveFinished);
|
||||
}
|
||||
|
||||
AStackWidget::~AStackWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int AStackWidget::count() const
|
||||
{
|
||||
return m_widgetLst.size();
|
||||
}
|
||||
|
||||
int AStackWidget::currentIndex() const
|
||||
{
|
||||
return m_curIndex;
|
||||
}
|
||||
|
||||
void AStackWidget::setDuration(int duration)
|
||||
{
|
||||
m_duration = duration;
|
||||
}
|
||||
|
||||
int AStackWidget::addWidget(QWidget * widget)
|
||||
{
|
||||
int index = indexOf(widget);
|
||||
if (index >= 0){
|
||||
return index;
|
||||
}
|
||||
widget->setParent(this);
|
||||
m_widgetLst.append(widget);
|
||||
return count() - 1;
|
||||
}
|
||||
|
||||
int AStackWidget::indexOf(QWidget * widget) const
|
||||
{
|
||||
return m_widgetLst.indexOf(widget);
|
||||
}
|
||||
|
||||
int AStackWidget::insertWidget(int index, QWidget * widget)
|
||||
{
|
||||
int curindex = indexOf(widget);
|
||||
if (curindex >= 0) {
|
||||
return curindex;
|
||||
}
|
||||
widget->setParent(this);
|
||||
m_widgetLst.insert(index, widget);
|
||||
return index;
|
||||
}
|
||||
|
||||
QWidget * AStackWidget::currentWidget() const
|
||||
{
|
||||
if (m_curIndex >= 0 && m_curIndex < count()){
|
||||
return m_widgetLst.at(m_curIndex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
QWidget * AStackWidget::widget(int index) const
|
||||
{
|
||||
if (index >= 0 && index < count()) {
|
||||
return m_widgetLst.at(index);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AStackWidget::removeWidget(QWidget * widget)
|
||||
{
|
||||
int index = indexOf(widget);
|
||||
if (index >= 0) {
|
||||
m_widgetLst.removeAll(widget);
|
||||
emit widgetRemoved(index);
|
||||
}
|
||||
}
|
||||
|
||||
void AStackWidget::setCurrentWidget(QWidget * widget)
|
||||
{
|
||||
int index = indexOf(widget);
|
||||
if (index >= 0 && m_curIndex != index) {
|
||||
setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void AStackWidget::setCurrentIndex(int index)
|
||||
{
|
||||
if (index >= 0 && m_curIndex != index) {
|
||||
m_lastIndex = m_curIndex;
|
||||
m_curIndex = index;
|
||||
moveAnimationStart();
|
||||
emit currentChanged(index);
|
||||
}
|
||||
}
|
||||
|
||||
void AStackWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
|
||||
int size = count();
|
||||
for (int i = 0; i < size; i++) {
|
||||
m_widgetLst.at(i)->resize(this->width(), this->height());
|
||||
}
|
||||
|
||||
if (m_moveAnimation->state() == QAbstractAnimation::Running) {
|
||||
moveAnimationStart();
|
||||
}
|
||||
else {
|
||||
setWidgetsVisible();
|
||||
onValueChanged(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AStackWidget::onValueChanged(const QVariant &value)
|
||||
{
|
||||
m_offset = value.toInt();
|
||||
m_widgetLst.at(m_curIndex)->move(m_offset, 0);
|
||||
if (m_curIndex > m_lastIndex) {
|
||||
m_widgetLst.at(m_lastIndex)->move(m_offset - this->width(), 0);
|
||||
} else if (m_curIndex < m_lastIndex){
|
||||
m_widgetLst.at(m_lastIndex)->move(this->width() + m_offset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void AStackWidget::moveAnimationStart()
|
||||
{
|
||||
m_moveAnimation->stop();
|
||||
setWidgetsVisible();
|
||||
int startOffset = m_offset;
|
||||
if (m_curIndex > m_lastIndex) {
|
||||
if (startOffset == 0) startOffset = this->width();
|
||||
else startOffset = this->width() - qAbs(startOffset);
|
||||
}
|
||||
else {
|
||||
if (startOffset == 0) startOffset = -this->width();
|
||||
else startOffset = qAbs(startOffset) - this->width();
|
||||
}
|
||||
m_moveAnimation->setDuration(qAbs(startOffset) * m_duration / this->width());
|
||||
m_moveAnimation->setStartValue(startOffset);
|
||||
m_moveAnimation->setEndValue(0);
|
||||
m_moveAnimation->start();
|
||||
}
|
||||
|
||||
void AStackWidget::setWidgetsVisible()
|
||||
{
|
||||
int size = count();
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (m_lastIndex == i || m_curIndex == i)
|
||||
m_widgetLst.at(i)->setVisible(true);
|
||||
else {
|
||||
m_widgetLst.at(i)->setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AStackWidget::onMoveFinished()
|
||||
{
|
||||
|
||||
}
|
||||
52
netfriend/astackwidget/astackwidget.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <QWidget>
|
||||
|
||||
class QPropertyAnimation;
|
||||
class AStackWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AStackWidget(QWidget *parent);
|
||||
~AStackWidget();
|
||||
|
||||
signals:
|
||||
void currentChanged(int index);
|
||||
void widgetRemoved(int index);
|
||||
|
||||
public:
|
||||
int count() const;
|
||||
int currentIndex() const;
|
||||
int addWidget(QWidget *widget);
|
||||
int indexOf(QWidget *widget) const;
|
||||
int insertWidget(int index, QWidget *widget);
|
||||
|
||||
QWidget *currentWidget() const;
|
||||
QWidget *widget(int index) const;
|
||||
|
||||
void removeWidget(QWidget *widget);
|
||||
void setDuration(int duration);
|
||||
|
||||
public slots:
|
||||
void setCurrentIndex(int index);
|
||||
void setCurrentWidget(QWidget *widget);
|
||||
|
||||
private slots:
|
||||
void onValueChanged(const QVariant &);
|
||||
void onMoveFinished();
|
||||
|
||||
private:
|
||||
void moveAnimationStart();
|
||||
void setWidgetsVisible();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
private:
|
||||
int m_offset;
|
||||
int m_curIndex;
|
||||
int m_lastIndex;
|
||||
|
||||
int m_duration;
|
||||
QPropertyAnimation *m_moveAnimation;
|
||||
QList<QWidget *> m_widgetLst;
|
||||
};
|
||||
16
netfriend/astackwidget/astackwidget.pro
Normal file
@@ -0,0 +1,16 @@
|
||||
QT += core gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
|
||||
|
||||
TARGET = astackwidget
|
||||
TEMPLATE = app
|
||||
DESTDIR = $$PWD/../bin
|
||||
CONFIG += warn_off
|
||||
|
||||
SOURCES += main.cpp
|
||||
SOURCES += astackwidget.cpp
|
||||
HEADERS += astackwidget.h
|
||||
|
||||
SOURCES += frmastackwidget.cpp
|
||||
HEADERS += frmastackwidget.h
|
||||
FORMS += frmastackwidget.ui
|
||||
42
netfriend/astackwidget/frmastackwidget.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "FrmAStackWidget.h"
|
||||
|
||||
#include <QButtonGroup>
|
||||
#include <QLabel>
|
||||
|
||||
FrmAStackWidget::FrmAStackWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
QList<QString> colorlst;
|
||||
colorlst << "#1abc9c";
|
||||
colorlst << "#2ecc71";
|
||||
colorlst << "#3498db";
|
||||
colorlst << "#9b59b6";
|
||||
colorlst << "#e74c3c";
|
||||
|
||||
QList<QPushButton *> btnlst;
|
||||
btnlst << ui.pushButton_1;
|
||||
btnlst << ui.pushButton_2;
|
||||
btnlst << ui.pushButton_3;
|
||||
btnlst << ui.pushButton_4;
|
||||
btnlst << ui.pushButton_5;
|
||||
|
||||
QButtonGroup *btnGroup = new QButtonGroup(this);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
connect(btnGroup, SIGNAL(idClicked(int)), ui.aStackwidget, SLOT(setCurrentIndex(int)));
|
||||
#else
|
||||
connect(btnGroup, SIGNAL(buttonClicked(int)), ui.aStackwidget, SLOT(setCurrentIndex(int)));
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
QLabel *label = new QLabel(ui.aStackwidget);
|
||||
label->setStyleSheet(QString("background-color:%1;color:#ffffff;").arg(colorlst.at(i)));
|
||||
label->setText(QString::number(i + 1));
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
int index = ui.aStackwidget->addWidget(label);
|
||||
btnGroup->addButton(btnlst.at(i), index);
|
||||
}
|
||||
}
|
||||
13
netfriend/astackwidget/frmastackwidget.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <QWidget>
|
||||
#include "ui_FrmAStackWidget.h"
|
||||
|
||||
class FrmAStackWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FrmAStackWidget(QWidget *parent = Q_NULLPTR);
|
||||
|
||||
private:
|
||||
Ui::FrmAStackWidgetClass ui;
|
||||
};
|
||||
94
netfriend/astackwidget/frmastackwidget.ui
Normal file
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FrmAStackWidgetClass</class>
|
||||
<widget class="QWidget" name="FrmAStackWidgetClass">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>FrmAStackWidget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_1">
|
||||
<property name="text">
|
||||
<string>PushButton1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_2">
|
||||
<property name="text">
|
||||
<string>PushButton2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_3">
|
||||
<property name="text">
|
||||
<string>PushButton3</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_4">
|
||||
<property name="text">
|
||||
<string>PushButton4</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_5">
|
||||
<property name="text">
|
||||
<string>PushButton5</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AStackWidget" name="aStackwidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AStackWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>astackwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
30
netfriend/astackwidget/main.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
#include "frmastackwidget.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
a.setFont(QFont("Microsoft Yahei", 9));
|
||||
|
||||
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
|
||||
#if _MSC_VER
|
||||
QTextCodec *codec = QTextCodec::codecForName("gbk");
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
#endif
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
QTextCodec::setCodecForCStrings(codec);
|
||||
QTextCodec::setCodecForTr(codec);
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
#endif
|
||||
|
||||
FrmAStackWidget w;
|
||||
w.setWindowTitle(QStringLiteral("动态StackWidget"));
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
BIN
netfriend/imagecropper/assets/README/001.png
Normal file
|
After Width: | Height: | Size: 288 KiB |
BIN
netfriend/imagecropper/assets/README/002.png
Normal file
|
After Width: | Height: | Size: 326 KiB |
BIN
netfriend/imagecropper/assets/README/003.png
Normal file
|
After Width: | Height: | Size: 197 KiB |
BIN
netfriend/imagecropper/assets/README/004.png
Normal file
|
After Width: | Height: | Size: 249 KiB |
BIN
netfriend/imagecropper/assets/README/005.png
Normal file
|
After Width: | Height: | Size: 197 KiB |
BIN
netfriend/imagecropper/assets/README/006.png
Normal file
|
After Width: | Height: | Size: 189 KiB |
BIN
netfriend/imagecropper/assets/README/cropper_shape.png
Normal file
|
After Width: | Height: | Size: 502 KiB |
BIN
netfriend/imagecropper/assets/README/import_functions.png
Normal file
|
After Width: | Height: | Size: 329 KiB |
99
netfriend/imagecropper/base/imagecropperdialog.h
Normal file
@@ -0,0 +1,99 @@
|
||||
#ifndef IMAGECROPPER_H
|
||||
#define IMAGECROPPER_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
#include <QPainter>
|
||||
#include <QLabel>
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
#include <QMessageBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "imagecropperlabel.h"
|
||||
|
||||
/*******************************************************
|
||||
* Loacl private class, which do image-cropping
|
||||
* Used in class ImageCropper
|
||||
*******************************************************/
|
||||
class ImageCropperDialogPrivate : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ImageCropperDialogPrivate(const QPixmap &imageIn, QPixmap &outputImage,
|
||||
int windowWidth, int windowHeight,
|
||||
CropperShape shape, QSize cropperSize = QSize())
|
||||
: QDialog(0)
|
||||
, outputImage(outputImage)
|
||||
{
|
||||
this->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
this->setWindowTitle("Image Cropper");
|
||||
this->setMouseTracking(true);
|
||||
this->setModal(true);
|
||||
|
||||
imageLabel = new ImageCropperLabel(windowWidth, windowHeight, this);
|
||||
imageLabel->setCropper(shape, cropperSize);
|
||||
imageLabel->setOutputShape(OutputShape::RECT);
|
||||
imageLabel->setOriginalImage(imageIn);
|
||||
imageLabel->enableOpacity(true);
|
||||
|
||||
QHBoxLayout *btnLayout = new QHBoxLayout();
|
||||
btnOk = new QPushButton("OK", this);
|
||||
btnCancel = new QPushButton("Cancel", this);
|
||||
btnLayout->addStretch();
|
||||
btnLayout->addWidget(btnOk);
|
||||
btnLayout->addWidget(btnCancel);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->addWidget(imageLabel);
|
||||
mainLayout->addLayout(btnLayout);
|
||||
|
||||
connect(btnOk, &QPushButton::clicked, this, [this]() {
|
||||
this->outputImage = this->imageLabel->getCroppedImage();
|
||||
this->close();
|
||||
});
|
||||
connect(btnCancel, &QPushButton::clicked, this, [this]() {
|
||||
this->outputImage = QPixmap();
|
||||
this->close();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
ImageCropperLabel *imageLabel;
|
||||
QPushButton *btnOk;
|
||||
QPushButton *btnCancel;
|
||||
QPixmap &outputImage;
|
||||
};
|
||||
|
||||
/*******************************************************************
|
||||
* class ImageCropperDialog
|
||||
* create a instane of class ImageCropperDialogPrivate
|
||||
* and get cropped image from the instance(after closing)
|
||||
********************************************************************/
|
||||
class ImageCropperDialog : QObject
|
||||
{
|
||||
public:
|
||||
static QPixmap getCroppedImage(const QString &filename, int windowWidth, int windowHeight,
|
||||
CropperShape cropperShape, QSize crooperSize = QSize())
|
||||
{
|
||||
QPixmap inputImage;
|
||||
QPixmap outputImage;
|
||||
|
||||
if (!inputImage.load(filename)) {
|
||||
QMessageBox::critical(0, "Error", "Load image failed!", QMessageBox::Ok);
|
||||
return outputImage;
|
||||
}
|
||||
|
||||
ImageCropperDialogPrivate *imageCropperDo =
|
||||
new ImageCropperDialogPrivate(inputImage, outputImage,
|
||||
windowWidth, windowHeight,
|
||||
cropperShape, crooperSize);
|
||||
imageCropperDo->exec();
|
||||
|
||||
return outputImage;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // IMAGECROPPER_H
|
||||
714
netfriend/imagecropper/base/imagecropperlabel.cpp
Normal file
@@ -0,0 +1,714 @@
|
||||
#include "imagecropperlabel.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QMouseEvent>
|
||||
#include <QDebug>
|
||||
#include <QBitmap>
|
||||
|
||||
ImageCropperLabel::ImageCropperLabel(int width, int height, QWidget* parent) :
|
||||
QLabel(parent)
|
||||
{
|
||||
this->setFixedSize(width, height);
|
||||
this->setAlignment(Qt::AlignCenter);
|
||||
this->setMouseTracking(true);
|
||||
|
||||
borderPen.setWidth(1);
|
||||
borderPen.setColor(Qt::white);
|
||||
borderPen.setDashPattern(QVector<qreal>() << 3 << 3 << 3 << 3);
|
||||
}
|
||||
|
||||
void ImageCropperLabel::setOriginalImage(const QPixmap &pixmap) {
|
||||
originalImage = pixmap;
|
||||
|
||||
int imgWidth = pixmap.width();
|
||||
int imgHeight = pixmap.height();
|
||||
int labelWidth = this->width();
|
||||
int labelHeight = this->height();
|
||||
int imgWidthInLabel;
|
||||
int imgHeightInLabel;
|
||||
|
||||
if (imgWidth * labelHeight < imgHeight * labelWidth) {
|
||||
scaledRate = labelHeight / double(imgHeight);
|
||||
imgHeightInLabel = labelHeight;
|
||||
imgWidthInLabel = int(scaledRate * imgWidth);
|
||||
imageRect.setRect((labelWidth - imgWidthInLabel) / 2, 0,
|
||||
imgWidthInLabel, imgHeightInLabel);
|
||||
}
|
||||
else {
|
||||
scaledRate = labelWidth / double(imgWidth);
|
||||
imgWidthInLabel = labelWidth;
|
||||
imgHeightInLabel = int(scaledRate * imgHeight);
|
||||
imageRect.setRect(0, (labelHeight - imgHeightInLabel) / 2,
|
||||
imgWidthInLabel, imgHeightInLabel);
|
||||
}
|
||||
|
||||
tempImage = originalImage.scaled(imgWidthInLabel, imgHeightInLabel,
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
this->setPixmap(tempImage);
|
||||
|
||||
if (cropperShape >= CropperShape::FIXED_RECT) {
|
||||
cropperRect.setWidth(int(cropperRect_.width() * scaledRate));
|
||||
cropperRect.setHeight(int(cropperRect_.height() * scaledRate));
|
||||
}
|
||||
resetCropperPos();
|
||||
}
|
||||
|
||||
|
||||
/*****************************************
|
||||
* set cropper's shape (and size)
|
||||
*****************************************/
|
||||
void ImageCropperLabel::setRectCropper() {
|
||||
cropperShape = CropperShape::RECT;
|
||||
resetCropperPos();
|
||||
}
|
||||
|
||||
void ImageCropperLabel::setSquareCropper() {
|
||||
cropperShape = CropperShape::SQUARE;
|
||||
resetCropperPos();
|
||||
}
|
||||
|
||||
void ImageCropperLabel::setEllipseCropper() {
|
||||
cropperShape = CropperShape::ELLIPSE;
|
||||
resetCropperPos();
|
||||
}
|
||||
|
||||
void ImageCropperLabel::setCircleCropper() {
|
||||
cropperShape = CropperShape::CIRCLE;
|
||||
resetCropperPos();
|
||||
}
|
||||
|
||||
void ImageCropperLabel::setFixedRectCropper(QSize size) {
|
||||
cropperShape = CropperShape::FIXED_RECT;
|
||||
cropperRect_.setSize(size);
|
||||
resetCropperPos();
|
||||
}
|
||||
|
||||
void ImageCropperLabel::setFixedEllipseCropper(QSize size) {
|
||||
cropperShape = CropperShape::FIXED_ELLIPSE;
|
||||
cropperRect_.setSize(size);
|
||||
resetCropperPos();
|
||||
}
|
||||
|
||||
// not recommended
|
||||
void ImageCropperLabel::setCropper(CropperShape shape, QSize size) {
|
||||
cropperShape = shape;
|
||||
cropperRect_.setSize(size);
|
||||
resetCropperPos();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Set cropper's fixed size
|
||||
*****************************************************************************/
|
||||
void ImageCropperLabel::setCropperFixedSize(int fixedWidth, int fixedHeight) {
|
||||
cropperRect_.setSize(QSize(fixedWidth, fixedHeight));
|
||||
resetCropperPos();
|
||||
}
|
||||
|
||||
void ImageCropperLabel::setCropperFixedWidth(int fixedWidth) {
|
||||
cropperRect_.setWidth(fixedWidth);
|
||||
resetCropperPos();
|
||||
}
|
||||
|
||||
void ImageCropperLabel::setCropperFixedHeight(int fixedHeight) {
|
||||
cropperRect_.setHeight(fixedHeight);
|
||||
resetCropperPos();
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* Move cropper to the center of the image
|
||||
* And resize to default
|
||||
**********************************************/
|
||||
void ImageCropperLabel::resetCropperPos() {
|
||||
int labelWidth = this->width();
|
||||
int labelHeight = this->height();
|
||||
|
||||
if (cropperShape == CropperShape::FIXED_RECT || cropperShape == CropperShape::FIXED_ELLIPSE) {
|
||||
cropperRect.setWidth(int(cropperRect_.width() * scaledRate));
|
||||
cropperRect.setHeight(int(cropperRect_.height() * scaledRate));
|
||||
}
|
||||
|
||||
switch (cropperShape) {
|
||||
case CropperShape::UNDEFINED:
|
||||
break;
|
||||
case CropperShape::FIXED_RECT:
|
||||
case CropperShape::FIXED_ELLIPSE: {
|
||||
cropperRect.setRect((labelWidth - cropperRect.width()) / 2,
|
||||
(labelHeight - cropperRect.height()) / 2,
|
||||
cropperRect.width(), cropperRect.height());
|
||||
break;
|
||||
}
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::ELLIPSE:
|
||||
case CropperShape::CIRCLE: {
|
||||
int imgWidth = tempImage.width();
|
||||
int imgHeight = tempImage.height();
|
||||
int edge = int((imgWidth > imgHeight ? imgHeight : imgWidth) * 3 / 4.0);
|
||||
cropperRect.setRect((labelWidth - edge) / 2, (labelHeight - edge) / 2, edge, edge);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QPixmap ImageCropperLabel::getCroppedImage() {
|
||||
return getCroppedImage(this->outputShape);
|
||||
}
|
||||
|
||||
QPixmap ImageCropperLabel::getCroppedImage(OutputShape shape) {
|
||||
int startX = int((cropperRect.left() - imageRect.left()) / scaledRate);
|
||||
int startY = int((cropperRect.top() - imageRect.top()) / scaledRate);
|
||||
int croppedWidth = int(cropperRect.width() / scaledRate);
|
||||
int croppedHeight = int(cropperRect.height() / scaledRate);
|
||||
|
||||
QPixmap resultImage(croppedWidth, croppedHeight);
|
||||
resultImage = originalImage.copy(startX, startY, croppedWidth, croppedHeight);
|
||||
|
||||
// Set ellipse mask (cut to ellipse shape)
|
||||
if (shape == OutputShape::ELLIPSE) {
|
||||
QSize size(croppedWidth, croppedHeight);
|
||||
QBitmap mask(size);
|
||||
QPainter painter(&mask);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
painter.fillRect(0, 0, size.width(), size.height(), Qt::white);
|
||||
painter.setBrush(QColor(0, 0, 0));
|
||||
painter.drawRoundedRect(0, 0, size.width(), size.height(), 99, 99);
|
||||
resultImage.setMask(mask);
|
||||
}
|
||||
|
||||
return resultImage;
|
||||
}
|
||||
|
||||
|
||||
void ImageCropperLabel::paintEvent(QPaintEvent *event) {
|
||||
// Draw original image
|
||||
QLabel::paintEvent(event);
|
||||
|
||||
// Draw cropper and set some effects
|
||||
switch (cropperShape) {
|
||||
case CropperShape::UNDEFINED:
|
||||
break;
|
||||
case CropperShape::FIXED_RECT:
|
||||
drawRectOpacity();
|
||||
break;
|
||||
case CropperShape::FIXED_ELLIPSE:
|
||||
drawEllipseOpacity();
|
||||
break;
|
||||
case CropperShape::RECT:
|
||||
drawRectOpacity();
|
||||
drawSquareEdge(!ONLY_FOUR_CORNERS);
|
||||
break;
|
||||
case CropperShape::SQUARE:
|
||||
drawRectOpacity();
|
||||
drawSquareEdge(ONLY_FOUR_CORNERS);
|
||||
break;
|
||||
case CropperShape::ELLIPSE:
|
||||
drawEllipseOpacity();
|
||||
drawSquareEdge(!ONLY_FOUR_CORNERS);
|
||||
break;
|
||||
case CropperShape::CIRCLE:
|
||||
drawEllipseOpacity();
|
||||
drawSquareEdge(ONLY_FOUR_CORNERS);
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw cropper rect
|
||||
if (isShowRectBorder) {
|
||||
QPainter painter(this);
|
||||
painter.setPen(borderPen);
|
||||
painter.drawRect(cropperRect);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageCropperLabel::drawSquareEdge(bool onlyFourCorners) {
|
||||
if (!isShowDragSquare)
|
||||
return;
|
||||
|
||||
// Four corners
|
||||
drawFillRect(cropperRect.topLeft(), dragSquareEdge, dragSquareColor);
|
||||
drawFillRect(cropperRect.topRight(), dragSquareEdge, dragSquareColor);
|
||||
drawFillRect(cropperRect.bottomLeft(), dragSquareEdge, dragSquareColor);
|
||||
drawFillRect(cropperRect.bottomRight(), dragSquareEdge, dragSquareColor);
|
||||
|
||||
// Four edges
|
||||
if (!onlyFourCorners) {
|
||||
int centralX = cropperRect.left() + cropperRect.width() / 2;
|
||||
int centralY = cropperRect.top() + cropperRect.height() / 2;
|
||||
drawFillRect(QPoint(cropperRect.left(), centralY), dragSquareEdge, dragSquareColor);
|
||||
drawFillRect(QPoint(centralX, cropperRect.top()), dragSquareEdge, dragSquareColor);
|
||||
drawFillRect(QPoint(cropperRect.right(), centralY), dragSquareEdge, dragSquareColor);
|
||||
drawFillRect(QPoint(centralX, cropperRect.bottom()), dragSquareEdge, dragSquareColor);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageCropperLabel::drawFillRect(QPoint centralPoint, int edge, QColor color) {
|
||||
QRect rect(centralPoint.x() - edge / 2, centralPoint.y() - edge / 2, edge, edge);
|
||||
QPainter painter(this);
|
||||
painter.fillRect(rect, color);
|
||||
}
|
||||
|
||||
// Opacity effect
|
||||
void ImageCropperLabel::drawOpacity(const QPainterPath& path) {
|
||||
QPainter painterOpac(this);
|
||||
painterOpac.setOpacity(opacity);
|
||||
painterOpac.fillPath(path, QBrush(Qt::black));
|
||||
}
|
||||
|
||||
void ImageCropperLabel::drawRectOpacity() {
|
||||
if (isShowOpacityEffect) {
|
||||
QPainterPath p1, p2, p;
|
||||
p1.addRect(imageRect);
|
||||
p2.addRect(cropperRect);
|
||||
p = p1.subtracted(p2);
|
||||
drawOpacity(p);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageCropperLabel::drawEllipseOpacity() {
|
||||
if (isShowOpacityEffect) {
|
||||
QPainterPath p1, p2, p;
|
||||
p1.addRect(imageRect);
|
||||
p2.addEllipse(cropperRect);
|
||||
p = p1.subtracted(p2);
|
||||
drawOpacity(p);
|
||||
}
|
||||
}
|
||||
|
||||
bool ImageCropperLabel::isPosNearDragSquare(const QPoint& pt1, const QPoint& pt2) {
|
||||
return abs(pt1.x() - pt2.x()) * 2 <= dragSquareEdge
|
||||
&& abs(pt1.y() - pt2.y()) * 2 <= dragSquareEdge;
|
||||
}
|
||||
|
||||
int ImageCropperLabel::getPosInCropperRect(const QPoint &pt) {
|
||||
if (isPosNearDragSquare(pt, QPoint(cropperRect.right(), cropperRect.center().y())))
|
||||
return RECT_RIGHT;
|
||||
if (isPosNearDragSquare(pt, cropperRect.bottomRight()))
|
||||
return RECT_BOTTOM_RIGHT;
|
||||
if (isPosNearDragSquare(pt, QPoint(cropperRect.center().x(), cropperRect.bottom())))
|
||||
return RECT_BOTTOM;
|
||||
if (isPosNearDragSquare(pt, cropperRect.bottomLeft()))
|
||||
return RECT_BOTTOM_LEFT;
|
||||
if (isPosNearDragSquare(pt, QPoint(cropperRect.left(), cropperRect.center().y())))
|
||||
return RECT_LEFT;
|
||||
if (isPosNearDragSquare(pt, cropperRect.topLeft()))
|
||||
return RECT_TOP_LEFT;
|
||||
if (isPosNearDragSquare(pt, QPoint(cropperRect.center().x(), cropperRect.top())))
|
||||
return RECT_TOP;
|
||||
if (isPosNearDragSquare(pt, cropperRect.topRight()))
|
||||
return RECT_TOP_RIGHT;
|
||||
if (cropperRect.contains(pt, true))
|
||||
return RECT_INSIDE;
|
||||
return RECT_OUTSIZD;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
*
|
||||
* Change mouse cursor type
|
||||
* Arrow, SizeHor, SizeVer, etc...
|
||||
*
|
||||
*************************************************/
|
||||
|
||||
void ImageCropperLabel::changeCursor() {
|
||||
switch (cursorPosInCropperRect) {
|
||||
case RECT_OUTSIZD:
|
||||
setCursor(Qt::ArrowCursor);
|
||||
break;
|
||||
case RECT_BOTTOM_RIGHT: {
|
||||
switch (cropperShape) {
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
setCursor(Qt::SizeFDiagCursor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_RIGHT: {
|
||||
switch (cropperShape) {
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_BOTTOM: {
|
||||
switch (cropperShape) {
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
setCursor(Qt::SizeVerCursor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_BOTTOM_LEFT: {
|
||||
switch (cropperShape) {
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
setCursor(Qt::SizeBDiagCursor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_LEFT: {
|
||||
switch (cropperShape) {
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_TOP_LEFT: {
|
||||
switch (cropperShape) {
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
setCursor(Qt::SizeFDiagCursor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_TOP: {
|
||||
switch (cropperShape) {
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
setCursor(Qt::SizeVerCursor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_TOP_RIGHT: {
|
||||
switch (cropperShape) {
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
setCursor(Qt::SizeBDiagCursor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_INSIDE: {
|
||||
setCursor(Qt::SizeAllCursor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* Mouse Events
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
void ImageCropperLabel::mousePressEvent(QMouseEvent *e) {
|
||||
currPos = lastPos = e->pos();
|
||||
isLButtonPressed = true;
|
||||
}
|
||||
|
||||
void ImageCropperLabel::mouseMoveEvent(QMouseEvent *e) {
|
||||
currPos = e->pos();
|
||||
if (!isCursorPosCalculated) {
|
||||
cursorPosInCropperRect = getPosInCropperRect(currPos);
|
||||
changeCursor();
|
||||
}
|
||||
|
||||
if (!isLButtonPressed)
|
||||
return;
|
||||
if (!imageRect.contains(currPos))
|
||||
return;
|
||||
|
||||
isCursorPosCalculated = true;
|
||||
|
||||
int xOffset = currPos.x() - lastPos.x();
|
||||
int yOffset = currPos.y() - lastPos.y();
|
||||
lastPos = currPos;
|
||||
|
||||
int disX = 0;
|
||||
int disY = 0;
|
||||
|
||||
// Move cropper
|
||||
switch (cursorPosInCropperRect) {
|
||||
case RECT_OUTSIZD:
|
||||
break;
|
||||
case RECT_BOTTOM_RIGHT: {
|
||||
disX = currPos.x() - cropperRect.left();
|
||||
disY = currPos.y() - cropperRect.top();
|
||||
switch (cropperShape) {
|
||||
case CropperShape::UNDEFINED:
|
||||
case CropperShape::FIXED_RECT:
|
||||
case CropperShape::FIXED_ELLIPSE:
|
||||
break;
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
setCursor(Qt::SizeFDiagCursor);
|
||||
if (disX >= cropperMinimumWidth && disY >= cropperMinimumHeight) {
|
||||
if (disX > disY && cropperRect.top() + disX <= imageRect.bottom()) {
|
||||
cropperRect.setRight(currPos.x());
|
||||
cropperRect.setBottom(cropperRect.top() + disX);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
else if (disX <= disY && cropperRect.left() + disY <= imageRect.right()) {
|
||||
cropperRect.setBottom(currPos.y());
|
||||
cropperRect.setRight(cropperRect.left() + disY);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
setCursor(Qt::SizeFDiagCursor);
|
||||
if (disX >= cropperMinimumWidth) {
|
||||
cropperRect.setRight(currPos.x());
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
if (disY >= cropperMinimumHeight) {
|
||||
cropperRect.setBottom(currPos.y());
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_RIGHT: {
|
||||
disX = currPos.x() - cropperRect.left();
|
||||
switch (cropperShape) {
|
||||
case CropperShape::UNDEFINED:
|
||||
case CropperShape::FIXED_RECT:
|
||||
case CropperShape::FIXED_ELLIPSE:
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
break;
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
if (disX >= cropperMinimumWidth) {
|
||||
cropperRect.setRight(currPos.x());
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_BOTTOM: {
|
||||
disY = currPos.y() - cropperRect.top();
|
||||
switch (cropperShape) {
|
||||
case CropperShape::UNDEFINED:
|
||||
case CropperShape::FIXED_RECT:
|
||||
case CropperShape::FIXED_ELLIPSE:
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
break;
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
if (disY >= cropperMinimumHeight) {
|
||||
cropperRect.setBottom(cropperRect.bottom() + yOffset);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_BOTTOM_LEFT: {
|
||||
disX = cropperRect.right() - currPos.x();
|
||||
disY = currPos.y() - cropperRect.top();
|
||||
switch (cropperShape) {
|
||||
case CropperShape::UNDEFINED:
|
||||
break;
|
||||
case CropperShape::FIXED_RECT:
|
||||
case CropperShape::FIXED_ELLIPSE:
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
if (disX >= cropperMinimumWidth) {
|
||||
cropperRect.setLeft(currPos.x());
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
if (disY >= cropperMinimumHeight) {
|
||||
cropperRect.setBottom(currPos.y());
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
break;
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
if (disX >= cropperMinimumWidth && disY >= cropperMinimumHeight) {
|
||||
if (disX > disY && cropperRect.top() + disX <= imageRect.bottom()) {
|
||||
cropperRect.setLeft(currPos.x());
|
||||
cropperRect.setBottom(cropperRect.top() + disX);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
else if (disX <= disY && cropperRect.right() - disY >= imageRect.left()) {
|
||||
cropperRect.setBottom(currPos.y());
|
||||
cropperRect.setLeft(cropperRect.right() - disY);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_LEFT: {
|
||||
disX = cropperRect.right() - currPos.x();
|
||||
switch (cropperShape) {
|
||||
case CropperShape::UNDEFINED:
|
||||
case CropperShape::FIXED_RECT:
|
||||
case CropperShape::FIXED_ELLIPSE:
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
break;
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
if (disX >= cropperMinimumHeight) {
|
||||
cropperRect.setLeft(cropperRect.left() + xOffset);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_TOP_LEFT: {
|
||||
disX = cropperRect.right() - currPos.x();
|
||||
disY = cropperRect.bottom() - currPos.y();
|
||||
switch (cropperShape) {
|
||||
case CropperShape::UNDEFINED:
|
||||
case CropperShape::FIXED_RECT:
|
||||
case CropperShape::FIXED_ELLIPSE:
|
||||
break;
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
if (disX >= cropperMinimumWidth) {
|
||||
cropperRect.setLeft(currPos.x());
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
if (disY >= cropperMinimumHeight) {
|
||||
cropperRect.setTop(currPos.y());
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
break;
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
if (disX >= cropperMinimumWidth && disY >= cropperMinimumHeight) {
|
||||
if (disX > disY && cropperRect.bottom() - disX >= imageRect.top()) {
|
||||
cropperRect.setLeft(currPos.x());
|
||||
cropperRect.setTop(cropperRect.bottom() - disX);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
else if (disX <= disY && cropperRect.right() - disY >= imageRect.left()) {
|
||||
cropperRect.setTop(currPos.y());
|
||||
cropperRect.setLeft(cropperRect.right() - disY);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_TOP: {
|
||||
disY = cropperRect.bottom() - currPos.y();
|
||||
switch (cropperShape) {
|
||||
case CropperShape::UNDEFINED:
|
||||
case CropperShape::FIXED_RECT:
|
||||
case CropperShape::FIXED_ELLIPSE:
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
break;
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
if (disY >= cropperMinimumHeight) {
|
||||
cropperRect.setTop(cropperRect.top() + yOffset);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_TOP_RIGHT: {
|
||||
disX = currPos.x() - cropperRect.left();
|
||||
disY = cropperRect.bottom() - currPos.y();
|
||||
switch (cropperShape) {
|
||||
case CropperShape::UNDEFINED:
|
||||
case CropperShape::FIXED_RECT:
|
||||
case CropperShape::FIXED_ELLIPSE:
|
||||
break;
|
||||
case CropperShape::RECT:
|
||||
case CropperShape::ELLIPSE:
|
||||
if (disX >= cropperMinimumWidth) {
|
||||
cropperRect.setRight(currPos.x());
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
if (disY >= cropperMinimumHeight) {
|
||||
cropperRect.setTop(currPos.y());
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
break;
|
||||
case CropperShape::SQUARE:
|
||||
case CropperShape::CIRCLE:
|
||||
if (disX >= cropperMinimumWidth && disY >= cropperMinimumHeight) {
|
||||
if (disX < disY && cropperRect.left() + disY <= imageRect.right()) {
|
||||
cropperRect.setTop(currPos.y());
|
||||
cropperRect.setRight(cropperRect.left() + disY);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
else if (disX >= disY && cropperRect.bottom() - disX >= imageRect.top()) {
|
||||
cropperRect.setRight(currPos.x());
|
||||
cropperRect.setTop(cropperRect.bottom() - disX);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECT_INSIDE: {
|
||||
// Make sure the cropperRect is entirely inside the imageRecct
|
||||
if (xOffset > 0) {
|
||||
if (cropperRect.right() + xOffset > imageRect.right())
|
||||
xOffset = 0;
|
||||
}
|
||||
else if (xOffset < 0) {
|
||||
if (cropperRect.left() + xOffset < imageRect.left())
|
||||
xOffset = 0;
|
||||
}
|
||||
if (yOffset > 0) {
|
||||
if (cropperRect.bottom() + yOffset > imageRect.bottom())
|
||||
yOffset = 0;
|
||||
}
|
||||
else if (yOffset < 0) {
|
||||
if (cropperRect.top() + yOffset < imageRect.top())
|
||||
yOffset = 0;
|
||||
}
|
||||
cropperRect.moveTo(cropperRect.left() + xOffset, cropperRect.top() + yOffset);
|
||||
emit croppedImageChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
void ImageCropperLabel::mouseReleaseEvent(QMouseEvent *) {
|
||||
isLButtonPressed = false;
|
||||
isCursorPosCalculated = false;
|
||||
setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
|
||||
168
netfriend/imagecropper/base/imagecropperlabel.h
Normal file
@@ -0,0 +1,168 @@
|
||||
#ifndef IMAGECROPPERLABEL_H
|
||||
#define IMAGECROPPERLABEL_H
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPixmap>
|
||||
#include <QPen>
|
||||
|
||||
enum class CropperShape {
|
||||
UNDEFINED = 0,
|
||||
RECT = 1,
|
||||
SQUARE = 2,
|
||||
FIXED_RECT = 3,
|
||||
ELLIPSE = 4,
|
||||
CIRCLE = 5,
|
||||
FIXED_ELLIPSE = 6
|
||||
};
|
||||
|
||||
enum class OutputShape {
|
||||
RECT = 0,
|
||||
ELLIPSE = 1
|
||||
};
|
||||
|
||||
enum class SizeType {
|
||||
fixedSize = 0,
|
||||
fitToMaxWidth = 1,
|
||||
fitToMaxHeight = 2,
|
||||
fitToMaxWidthHeight = 3,
|
||||
};
|
||||
|
||||
class ImageCropperLabel : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ImageCropperLabel(int width, int height, QWidget *parent);
|
||||
|
||||
void setOriginalImage(const QPixmap &pixmap);
|
||||
void setOutputShape(OutputShape shape) { outputShape = shape; }
|
||||
QPixmap getCroppedImage();
|
||||
QPixmap getCroppedImage(OutputShape shape);
|
||||
|
||||
/*****************************************
|
||||
* Set cropper's shape
|
||||
*****************************************/
|
||||
void setRectCropper();
|
||||
void setSquareCropper();
|
||||
void setEllipseCropper();
|
||||
void setCircleCropper();
|
||||
void setFixedRectCropper(QSize size);
|
||||
void setFixedEllipseCropper(QSize size);
|
||||
void setCropper(CropperShape shape, QSize size); // not recommended
|
||||
|
||||
/*****************************************************************************
|
||||
* Set cropper's fixed size
|
||||
*****************************************************************************/
|
||||
void setCropperFixedSize(int fixedWidth, int fixedHeight);
|
||||
void setCropperFixedWidth(int fixedWidht);
|
||||
void setCropperFixedHeight(int fixedHeight);
|
||||
|
||||
/*****************************************************************************
|
||||
* Set cropper's minimum size
|
||||
* default: the twice of minimum of the edge lenght of drag square
|
||||
*****************************************************************************/
|
||||
void setCropperMinimumSize(int minWidth, int minHeight)
|
||||
{
|
||||
cropperMinimumWidth = minWidth;
|
||||
cropperMinimumHeight = minHeight;
|
||||
}
|
||||
void setCropperMinimumWidth(int minWidth) { cropperMinimumWidth = minWidth; }
|
||||
void setCropperMinimumHeight(int minHeight) { cropperMinimumHeight = minHeight; }
|
||||
|
||||
/*************************************************
|
||||
* Set the size, color, visibility of rectangular border
|
||||
*************************************************/
|
||||
void setShowRectBorder(bool show) { isShowRectBorder = show; }
|
||||
QPen getBorderPen() { return borderPen; }
|
||||
void setBorderPen(const QPen &pen) { borderPen = pen; }
|
||||
|
||||
/*************************************************
|
||||
* Set the size, color of drag square
|
||||
*************************************************/
|
||||
void setShowDragSquare(bool show) { isShowDragSquare = show; }
|
||||
void setDragSquareEdge(int edge) { dragSquareEdge = (edge >= 3 ? edge : 3); }
|
||||
void setDragSquareColor(const QColor &color) { dragSquareColor = color; }
|
||||
|
||||
/*****************************************
|
||||
* Opacity Effect
|
||||
*****************************************/
|
||||
void enableOpacity(bool b = true) { isShowOpacityEffect = b; }
|
||||
void setOpacity(double newOpacity) { opacity = newOpacity; }
|
||||
|
||||
signals:
|
||||
void croppedImageChanged();
|
||||
|
||||
protected:
|
||||
/*****************************************
|
||||
* Event
|
||||
*****************************************/
|
||||
virtual void paintEvent(QPaintEvent *event) override;
|
||||
virtual void mousePressEvent(QMouseEvent *e) override;
|
||||
virtual void mouseMoveEvent(QMouseEvent *e) override;
|
||||
virtual void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
|
||||
private:
|
||||
/***************************************
|
||||
* Draw shapes
|
||||
***************************************/
|
||||
void drawFillRect(QPoint centralPoint, int edge, QColor color);
|
||||
void drawRectOpacity();
|
||||
void drawEllipseOpacity();
|
||||
void drawOpacity(const QPainterPath &path); // shadow effect
|
||||
void drawSquareEdge(bool onlyFourCorners);
|
||||
|
||||
/***************************************
|
||||
* Other utility methods
|
||||
***************************************/
|
||||
int getPosInCropperRect(const QPoint &pt);
|
||||
bool isPosNearDragSquare(const QPoint &pt1, const QPoint &pt2);
|
||||
void resetCropperPos();
|
||||
void changeCursor();
|
||||
|
||||
enum {
|
||||
RECT_OUTSIZD = 0,
|
||||
RECT_INSIDE = 1,
|
||||
RECT_TOP_LEFT,
|
||||
RECT_TOP,
|
||||
RECT_TOP_RIGHT,
|
||||
RECT_RIGHT,
|
||||
RECT_BOTTOM_RIGHT,
|
||||
RECT_BOTTOM,
|
||||
RECT_BOTTOM_LEFT,
|
||||
RECT_LEFT
|
||||
};
|
||||
|
||||
const bool ONLY_FOUR_CORNERS = true;
|
||||
|
||||
private:
|
||||
QPixmap originalImage;
|
||||
QPixmap tempImage;
|
||||
|
||||
bool isShowRectBorder = true;
|
||||
QPen borderPen;
|
||||
|
||||
CropperShape cropperShape = CropperShape::UNDEFINED;
|
||||
OutputShape outputShape = OutputShape::RECT;
|
||||
|
||||
QRect imageRect; // the whole image area in the label (not real size)
|
||||
QRect cropperRect; // a rectangle frame to choose image area (not real size)
|
||||
QRect cropperRect_; // cropper rect (real size)
|
||||
double scaledRate = 1.0;
|
||||
|
||||
bool isLButtonPressed = false;
|
||||
bool isCursorPosCalculated = false;
|
||||
int cursorPosInCropperRect = RECT_OUTSIZD;
|
||||
QPoint lastPos;
|
||||
QPoint currPos;
|
||||
|
||||
bool isShowDragSquare = true;
|
||||
int dragSquareEdge = 8;
|
||||
QColor dragSquareColor = Qt::white;
|
||||
|
||||
int cropperMinimumWidth = dragSquareEdge * 2;
|
||||
int cropperMinimumHeight = dragSquareEdge * 2;
|
||||
|
||||
bool isShowOpacityEffect = false;
|
||||
double opacity = 0.6;
|
||||
};
|
||||
|
||||
#endif // IMAGECROPPERLABEL_H
|
||||
415
netfriend/imagecropper/example/imagecropperdemo.cpp
Normal file
@@ -0,0 +1,415 @@
|
||||
#include "imagecropperdemo.h"
|
||||
#include <QFormLayout>
|
||||
#include <QColorDialog>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
ImageCropperDemo::ImageCropperDemo(QWidget* parent) :
|
||||
QDialog(parent)
|
||||
{
|
||||
setupLayout();
|
||||
init();
|
||||
|
||||
this->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
this->setWindowTitle("Image Cropper Demo");
|
||||
}
|
||||
|
||||
|
||||
void ImageCropperDemo::setupLayout() {
|
||||
imgCropperLabel = new ImageCropperLabel(600, 500, this);
|
||||
imgCropperLabel->setFrameStyle(1);
|
||||
|
||||
comboOutputShape = new QComboBox(this);
|
||||
comboCropperShape = new QComboBox(this);
|
||||
|
||||
labelPreviewImage = new QLabel(this);
|
||||
|
||||
editOriginalImagePath = new QLineEdit(this);
|
||||
btnChooseOriginalImagePath = new QPushButton(this);
|
||||
QHBoxLayout* hOriginalImagePathLayout = new QHBoxLayout();
|
||||
hOriginalImagePathLayout->addWidget(editOriginalImagePath);
|
||||
hOriginalImagePathLayout->addWidget(btnChooseOriginalImagePath);
|
||||
|
||||
editCropperFixedWidth = new QLineEdit(this);
|
||||
editCropperFixedHeight = new QLineEdit(this);
|
||||
QHBoxLayout* hCropperFixedSizeLayout = new QHBoxLayout();
|
||||
hCropperFixedSizeLayout->addWidget(editCropperFixedWidth);
|
||||
hCropperFixedSizeLayout->addWidget(editCropperFixedHeight);
|
||||
|
||||
editCropperMinWidth = new QLineEdit("8", this);
|
||||
editCropperMinHeight = new QLineEdit("8", this);
|
||||
QHBoxLayout* hCropperMinSizeLayout = new QHBoxLayout();
|
||||
hCropperMinSizeLayout->addWidget(editCropperMinWidth);
|
||||
hCropperMinSizeLayout->addWidget(editCropperMinHeight);
|
||||
|
||||
checkEnableOpacity = new QCheckBox(this);
|
||||
sliderOpacity = new QSlider(Qt::Horizontal, this);
|
||||
|
||||
checkShowDragSquare = new QCheckBox(this);
|
||||
editDragSquareEdge = new QLineEdit("8", this);
|
||||
checkShowRectBorder = new QCheckBox(this);
|
||||
|
||||
labelRectBorderColor = new QLabel(this);
|
||||
btnChooseRectBorderCorlor = new QPushButton(this);
|
||||
QHBoxLayout* hRectBorderColorLayout = new QHBoxLayout();
|
||||
hRectBorderColorLayout->addWidget(labelRectBorderColor);
|
||||
hRectBorderColorLayout->addWidget(btnChooseRectBorderCorlor);
|
||||
|
||||
labelDragSquareColor = new QLabel(this);
|
||||
btnChooseDragSquareColor = new QPushButton(this);
|
||||
QHBoxLayout* hDragSquareColorLayout = new QHBoxLayout();
|
||||
hDragSquareColorLayout->addWidget(labelDragSquareColor);
|
||||
hDragSquareColorLayout->addWidget(btnChooseDragSquareColor);
|
||||
|
||||
QFormLayout* formLayout1 = new QFormLayout();
|
||||
formLayout1->addRow(new QLabel("Preview:"), labelPreviewImage);
|
||||
formLayout1->addRow(new QLabel("OriginalImage:", this), hOriginalImagePathLayout);
|
||||
formLayout1->addRow(new QLabel("OutputShape:", this), comboOutputShape);
|
||||
formLayout1->addRow(new QLabel("CropperShape:", this), comboCropperShape);
|
||||
formLayout1->addRow(new QLabel("FixedSize:", this), hCropperFixedSizeLayout);
|
||||
formLayout1->addRow(new QLabel("MinimumSize:", this), hCropperMinSizeLayout);
|
||||
|
||||
QFormLayout* formLayout2 = new QFormLayout();
|
||||
formLayout2->addRow(new QLabel("EnableOpacity:", this), checkEnableOpacity);
|
||||
formLayout2->addRow(new QLabel("Opacity:", this), sliderOpacity);
|
||||
|
||||
QFormLayout* formLayout3 = new QFormLayout();
|
||||
formLayout3->addRow(new QLabel("ShowDragSquare:", this), checkShowDragSquare);
|
||||
formLayout3->addRow(new QLabel("DragSquareEdge:", this), editDragSquareEdge);
|
||||
formLayout3->addRow(new QLabel("DragSquareColor:", this), hDragSquareColorLayout);
|
||||
|
||||
QFormLayout* formLayout4 = new QFormLayout();
|
||||
formLayout4->addRow(new QLabel("ShowRectBorder:", this), checkShowRectBorder);
|
||||
formLayout4->addRow(new QLabel("RectBorderColor:", this), hRectBorderColorLayout);
|
||||
|
||||
btnSavePreview = new QPushButton("Save", this);
|
||||
btnQuit = new QPushButton("Quit", this);
|
||||
QHBoxLayout* btnLayout = new QHBoxLayout();
|
||||
btnLayout->addStretch();
|
||||
btnLayout->addWidget(btnSavePreview);
|
||||
btnLayout->addStretch();
|
||||
btnLayout->addWidget(btnQuit);
|
||||
btnLayout->addStretch();
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
vLayout->addLayout(formLayout1);
|
||||
vLayout->addStretch();
|
||||
vLayout->addLayout(formLayout2);
|
||||
vLayout->addStretch();
|
||||
vLayout->addLayout(formLayout3);
|
||||
vLayout->addStretch();
|
||||
vLayout->addLayout(formLayout4);
|
||||
vLayout->addStretch();
|
||||
vLayout->addLayout(btnLayout);
|
||||
|
||||
mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->addWidget(imgCropperLabel);
|
||||
mainLayout->addLayout(vLayout);
|
||||
}
|
||||
|
||||
void ImageCropperDemo::init() {
|
||||
imgCropperLabel->setRectCropper();
|
||||
editCropperFixedWidth->setEnabled(false);
|
||||
editCropperFixedHeight->setEnabled(false);
|
||||
|
||||
labelPreviewImage->setFixedSize(96, 96);
|
||||
labelPreviewImage->setAlignment(Qt::AlignCenter);
|
||||
labelPreviewImage->setFrameStyle(QFrame::Panel | QFrame::Sunken);
|
||||
connect(imgCropperLabel, &ImageCropperLabel::croppedImageChanged,
|
||||
this, &ImageCropperDemo::onUpdatePreview);
|
||||
|
||||
btnChooseOriginalImagePath->setIcon(QIcon("res/select-file.ico"));
|
||||
btnChooseOriginalImagePath->setFixedWidth(30);
|
||||
connect(btnChooseOriginalImagePath, &QPushButton::clicked,
|
||||
this, &ImageCropperDemo::onChooseOriginalImage);
|
||||
|
||||
comboOutputShape->addItem("Rect/Square");
|
||||
comboOutputShape->addItem("Ellipse/Circle");
|
||||
connect(comboOutputShape, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(onOutputShapeChanged(int)));
|
||||
|
||||
comboCropperShape->addItem("Rect");
|
||||
comboCropperShape->addItem("Square");
|
||||
comboCropperShape->addItem("FixedRect");
|
||||
comboCropperShape->addItem("Ellipse");
|
||||
comboCropperShape->addItem("Circle");
|
||||
comboCropperShape->addItem("FixedEllipse");
|
||||
connect(comboCropperShape, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(onCropperShapeChanged(int)));
|
||||
|
||||
connect(editCropperFixedWidth, &QLineEdit::textChanged,
|
||||
this, &ImageCropperDemo::onFixedWidthChanged);
|
||||
connect(editCropperFixedHeight, &QLineEdit::textChanged,
|
||||
this, &ImageCropperDemo::onFixedHeightChanged);
|
||||
connect(editCropperMinWidth, &QLineEdit::textChanged,
|
||||
this, &ImageCropperDemo::onMinWidthChanged);
|
||||
connect(editCropperMinHeight, &QLineEdit::textChanged,
|
||||
this, &ImageCropperDemo::onMinHeightChanged);
|
||||
|
||||
checkEnableOpacity->setCheckState(Qt::Checked);
|
||||
imgCropperLabel->enableOpacity(true);
|
||||
connect(checkEnableOpacity, &QCheckBox::stateChanged,
|
||||
this, &ImageCropperDemo::onEnableOpacityChanged);
|
||||
|
||||
checkShowDragSquare->setCheckState(Qt::Checked);
|
||||
imgCropperLabel->setShowDragSquare(true);
|
||||
connect(checkShowDragSquare, &QCheckBox::stateChanged,
|
||||
this, &ImageCropperDemo::onShowDragSquareChanged);
|
||||
connect(editDragSquareEdge, &QLineEdit::textChanged,
|
||||
this, &ImageCropperDemo::onDragSquareEdgeChanged);
|
||||
|
||||
sliderOpacity->setRange(0, 100);
|
||||
sliderOpacity->setValue(60);
|
||||
connect(sliderOpacity, &QSlider::valueChanged,
|
||||
this, &ImageCropperDemo::onOpacityChanged);
|
||||
|
||||
checkShowRectBorder->setCheckState(Qt::Checked);
|
||||
connect(checkShowRectBorder, &QCheckBox::stateChanged,
|
||||
this, &ImageCropperDemo::onShowRectBorder);
|
||||
|
||||
setLabelColor(labelRectBorderColor, Qt::white);
|
||||
btnChooseRectBorderCorlor->setIcon(QIcon("res/color-palette.ico"));
|
||||
btnChooseRectBorderCorlor->setFixedWidth(40);
|
||||
connect(btnChooseRectBorderCorlor, &QPushButton::clicked,
|
||||
this, &ImageCropperDemo::onChooseRectBorderColor);
|
||||
|
||||
setLabelColor(labelDragSquareColor, Qt::white);
|
||||
btnChooseDragSquareColor->setIcon(QIcon("res/color-palette.ico"));
|
||||
btnChooseDragSquareColor->setFixedWidth(40);
|
||||
connect(btnChooseDragSquareColor, &QPushButton::clicked,
|
||||
this, &ImageCropperDemo::onChooseDragSquareColor);
|
||||
|
||||
connect(btnSavePreview, &QPushButton::clicked,
|
||||
this, &ImageCropperDemo::onSaveCroppedImage);
|
||||
connect(btnQuit, &QPushButton::clicked,
|
||||
this, &ImageCropperDemo::close);
|
||||
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* slots
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
void ImageCropperDemo::onChooseOriginalImage() {
|
||||
QString filename = QFileDialog::getOpenFileName(this, "Select a picture", "",
|
||||
"picture (*.jpg *.png *.bmp)");
|
||||
if (filename.isNull())
|
||||
return;
|
||||
|
||||
QPixmap pixmap;
|
||||
if (!pixmap.load(filename)) {
|
||||
QMessageBox::critical(this, "Error", "Load image failed", QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
editOriginalImagePath->setText(filename);
|
||||
imgCropperLabel->setOriginalImage(pixmap);
|
||||
imgCropperLabel->update();
|
||||
onUpdatePreview();
|
||||
labelPreviewImage->setFrameStyle(0);
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onOutputShapeChanged(int idx) {
|
||||
// Output: Rectangular
|
||||
if (idx == 0)
|
||||
imgCropperLabel->setOutputShape(OutputShape::RECT);
|
||||
else
|
||||
imgCropperLabel->setOutputShape(OutputShape::ELLIPSE);
|
||||
onUpdatePreview();
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onCropperShapeChanged(int idx) {
|
||||
switch (CropperShape(idx + 1)) {
|
||||
case CropperShape::RECT: {
|
||||
imgCropperLabel->setRectCropper();
|
||||
editCropperFixedWidth->setEnabled(false);
|
||||
editCropperFixedHeight->setEnabled(false);
|
||||
editCropperMinWidth->setEnabled(true);
|
||||
editCropperMinHeight->setEnabled(true);
|
||||
checkShowDragSquare->setEnabled(true);
|
||||
editDragSquareEdge->setEnabled(true);
|
||||
btnChooseDragSquareColor->setEnabled(true);
|
||||
break;
|
||||
}
|
||||
case CropperShape::SQUARE: {
|
||||
imgCropperLabel->setSquareCropper();
|
||||
editCropperFixedWidth->setEnabled(false);
|
||||
editCropperFixedHeight->setEnabled(false);
|
||||
editCropperMinWidth->setEnabled(true);
|
||||
editCropperMinHeight->setEnabled(true);
|
||||
checkShowDragSquare->setEnabled(true);
|
||||
editDragSquareEdge->setEnabled(true);
|
||||
btnChooseDragSquareColor->setEnabled(true);
|
||||
break;
|
||||
}
|
||||
case CropperShape::FIXED_RECT: {
|
||||
imgCropperLabel->setFixedRectCropper(QSize(64, 64));
|
||||
editCropperFixedWidth->setEnabled(true);
|
||||
editCropperFixedHeight->setEnabled(true);
|
||||
editCropperMinWidth->setEnabled(false);
|
||||
editCropperMinHeight->setEnabled(false);
|
||||
editCropperFixedWidth->setText("64");
|
||||
editCropperFixedHeight->setText("64");
|
||||
checkShowDragSquare->setEnabled(false);
|
||||
editDragSquareEdge->setEnabled(false);
|
||||
btnChooseDragSquareColor->setEnabled(false);
|
||||
break;
|
||||
}
|
||||
case CropperShape::ELLIPSE: {
|
||||
imgCropperLabel->setEllipseCropper();
|
||||
editCropperFixedWidth->setEnabled(false);
|
||||
editCropperFixedHeight->setEnabled(false);
|
||||
editCropperMinWidth->setEnabled(true);
|
||||
editCropperMinHeight->setEnabled(true);
|
||||
checkShowDragSquare->setEnabled(true);
|
||||
editDragSquareEdge->setEnabled(true);
|
||||
btnChooseDragSquareColor->setEnabled(true);
|
||||
break;
|
||||
}
|
||||
case CropperShape::CIRCLE: {
|
||||
imgCropperLabel->setCircleCropper();
|
||||
editCropperFixedWidth->setEnabled(false);
|
||||
editCropperFixedHeight->setEnabled(false);
|
||||
editCropperMinWidth->setEnabled(true);
|
||||
editCropperMinHeight->setEnabled(true);
|
||||
checkShowDragSquare->setEnabled(true);
|
||||
editDragSquareEdge->setEnabled(true);
|
||||
btnChooseDragSquareColor->setEnabled(true);
|
||||
break;
|
||||
}
|
||||
case CropperShape::FIXED_ELLIPSE:
|
||||
imgCropperLabel->setFixedEllipseCropper(QSize(64, 64));
|
||||
editCropperFixedWidth->setEnabled(true);
|
||||
editCropperFixedHeight->setEnabled(true);
|
||||
editCropperMinWidth->setEnabled(false);
|
||||
editCropperMinHeight->setEnabled(false);
|
||||
editCropperFixedWidth->setText("64");
|
||||
editCropperFixedHeight->setText("64");
|
||||
checkShowDragSquare->setEnabled(false);
|
||||
editDragSquareEdge->setEnabled(false);
|
||||
btnChooseDragSquareColor->setEnabled(false);
|
||||
break;
|
||||
case CropperShape::UNDEFINED:
|
||||
break;
|
||||
}
|
||||
|
||||
imgCropperLabel->update();
|
||||
onUpdatePreview();
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onEnableOpacityChanged(int state) {
|
||||
if (state == Qt::Checked) {
|
||||
sliderOpacity->setEnabled(true);
|
||||
imgCropperLabel->enableOpacity(true);
|
||||
}
|
||||
else {
|
||||
sliderOpacity->setEnabled(false);
|
||||
imgCropperLabel->enableOpacity(false);
|
||||
}
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onShowDragSquareChanged(int state) {
|
||||
if (state == Qt::Checked) {
|
||||
editDragSquareEdge->setEnabled(true);
|
||||
btnChooseDragSquareColor->setEnabled(true);
|
||||
imgCropperLabel->setShowDragSquare(true);
|
||||
}
|
||||
else {
|
||||
editDragSquareEdge->setEnabled(false);
|
||||
btnChooseDragSquareColor->setEnabled(false);
|
||||
imgCropperLabel->setShowDragSquare(false);
|
||||
}
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onDragSquareEdgeChanged(QString edge) {
|
||||
imgCropperLabel->setDragSquareEdge(edge.toInt());
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onOpacityChanged(int val) {
|
||||
imgCropperLabel->setOpacity(val / 100.0);
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onFixedWidthChanged(QString width) {
|
||||
imgCropperLabel->setCropperFixedWidth(width.toInt());
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onFixedHeightChanged(QString height) {
|
||||
imgCropperLabel->setCropperFixedHeight(height.toInt());
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onMinWidthChanged(QString width) {
|
||||
imgCropperLabel->setCropperMinimumWidth(width.toInt());
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onMinHeightChanged(QString height) {
|
||||
imgCropperLabel->setMinimumHeight(height.toInt());
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onShowRectBorder(int state) {
|
||||
if (state == Qt::Checked) {
|
||||
btnChooseRectBorderCorlor->setEnabled(true);
|
||||
imgCropperLabel->setShowRectBorder(true);
|
||||
}
|
||||
else {
|
||||
btnChooseRectBorderCorlor->setEnabled(false);
|
||||
imgCropperLabel->setShowRectBorder(false);
|
||||
}
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onChooseRectBorderColor() {
|
||||
QColor color = QColorDialog::getColor(imgCropperLabel->getBorderPen().color(), this);
|
||||
if (color.isValid()) {
|
||||
setLabelColor(labelRectBorderColor, color);
|
||||
QPen pen = imgCropperLabel->getBorderPen();
|
||||
pen.setColor(color);
|
||||
imgCropperLabel->setBorderPen(pen);
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onChooseDragSquareColor() {
|
||||
QColor color = QColorDialog::getColor(Qt::white, this);
|
||||
if (color.isValid()) {
|
||||
setLabelColor(labelDragSquareColor, color);
|
||||
imgCropperLabel->setDragSquareColor(color);
|
||||
imgCropperLabel->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onUpdatePreview() {
|
||||
QPixmap preview = imgCropperLabel->getCroppedImage();
|
||||
preview = preview.scaled(labelPreviewImage->width(), labelPreviewImage->height(),
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
labelPreviewImage->setPixmap(preview);
|
||||
}
|
||||
|
||||
void ImageCropperDemo::onSaveCroppedImage() {
|
||||
const QPixmap* pixmap = labelPreviewImage->pixmap();
|
||||
if (!pixmap) {
|
||||
QMessageBox::information(this, "Error", "There is no cropped image to save.", QMessageBox::Ok);
|
||||
return ;
|
||||
}
|
||||
|
||||
QString filename = QFileDialog::getSaveFileName(this, "Save cropped image", "", "picture (*.png)");
|
||||
if (!filename.isNull()) {
|
||||
if (imgCropperLabel->getCroppedImage().save(filename, "PNG"))
|
||||
QMessageBox::information(this, "Prompt", "Saved successfully", QMessageBox::Ok);
|
||||
else
|
||||
QMessageBox::information(this, "Error", "Save image failed!", QMessageBox::Ok);
|
||||
}
|
||||
}
|
||||
|
||||
85
netfriend/imagecropper/example/imagecropperdemo.h
Normal file
@@ -0,0 +1,85 @@
|
||||
#ifndef TESTIMAGECROPPERLABEL_H
|
||||
#define TESTIMAGECROPPERLABEL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDialog>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
#include <QCheckBox>
|
||||
#include <QPushButton>
|
||||
#include <QSlider>
|
||||
|
||||
#include "../base/imagecropperlabel.h"
|
||||
|
||||
class ImageCropperDemo : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ImageCropperDemo(QWidget* parent = 0);
|
||||
|
||||
void setupLayout();
|
||||
|
||||
void init();
|
||||
|
||||
public slots:
|
||||
void onOutputShapeChanged(int idx);
|
||||
void onCropperShapeChanged(int idx);
|
||||
void onEnableOpacityChanged(int state);
|
||||
void onShowDragSquareChanged(int state);
|
||||
void onDragSquareEdgeChanged(QString edge);
|
||||
void onOpacityChanged(int val);
|
||||
void onFixedWidthChanged(QString width);
|
||||
void onFixedHeightChanged(QString height);
|
||||
void onMinWidthChanged(QString width);
|
||||
void onMinHeightChanged(QString height);
|
||||
void onShowRectBorder(int state);
|
||||
void onChooseRectBorderColor();
|
||||
void onChooseDragSquareColor();
|
||||
|
||||
void onChooseOriginalImage();
|
||||
void onUpdatePreview();
|
||||
void onSaveCroppedImage();
|
||||
|
||||
private:
|
||||
void setLabelColor(QLabel* label, QColor color) {
|
||||
QPixmap pixmap(QSize(80, 25));
|
||||
pixmap.fill(color);
|
||||
label->setPixmap(pixmap);
|
||||
}
|
||||
|
||||
private:
|
||||
ImageCropperLabel* imgCropperLabel;
|
||||
QHBoxLayout* mainLayout;
|
||||
|
||||
QLabel* labelPreviewImage;
|
||||
|
||||
QComboBox* comboOutputShape;
|
||||
QComboBox* comboCropperShape;
|
||||
|
||||
QLineEdit* editOriginalImagePath;
|
||||
QPushButton* btnChooseOriginalImagePath;
|
||||
|
||||
QLineEdit* editCropperFixedWidth;
|
||||
QLineEdit* editCropperFixedHeight;
|
||||
QLineEdit* editCropperMinWidth;
|
||||
QLineEdit* editCropperMinHeight;
|
||||
|
||||
QCheckBox* checkShowDragSquare;
|
||||
QCheckBox* checkEnableOpacity;
|
||||
QSlider* sliderOpacity;
|
||||
QLineEdit* editDragSquareEdge;
|
||||
|
||||
QCheckBox* checkShowRectBorder;
|
||||
QLabel* labelRectBorderColor;
|
||||
QPushButton* btnChooseRectBorderCorlor;
|
||||
|
||||
QLabel* labelDragSquareColor;
|
||||
QPushButton* btnChooseDragSquareColor;
|
||||
|
||||
QPushButton* btnSavePreview;
|
||||
QPushButton* btnQuit;
|
||||
};
|
||||
|
||||
#endif // TESTIMAGECROPPERLABEL_H
|
||||
11
netfriend/imagecropper/example/main.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
62
netfriend/imagecropper/example/mainwindow.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "mainwindow.h"
|
||||
#include "imagecropperdemo.h"
|
||||
|
||||
#include "../base/imagecropperdialog.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFileDialog>
|
||||
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
setupLayout();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindow::setupLayout() {
|
||||
QWidget* centralWidget = new QWidget(this);
|
||||
|
||||
btnCustomCrop = new QPushButton("Custom Crop", centralWidget);
|
||||
btnSimpleCrop = new QPushButton("Simple Crop", centralWidget);
|
||||
|
||||
QVBoxLayout* mainLayout = new QVBoxLayout(centralWidget);
|
||||
mainLayout->addWidget(btnCustomCrop);
|
||||
mainLayout->addWidget(btnSimpleCrop);
|
||||
this->setCentralWidget(centralWidget);
|
||||
|
||||
connect(btnCustomCrop, &QPushButton::clicked, this, &MainWindow::onCustomCrop);
|
||||
connect(btnSimpleCrop, &QPushButton::clicked, this, &MainWindow::onSimpleCrop);
|
||||
}
|
||||
|
||||
void MainWindow::onCustomCrop() {
|
||||
ImageCropperDemo* dialog = new ImageCropperDemo(this);
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
void MainWindow::onSimpleCrop() {
|
||||
QMessageBox::information(this, "Prompt", "Please select a picture", QMessageBox::Ok);
|
||||
QString filename = QFileDialog::getOpenFileName(this, "Select image", "", "image (*.png *.jpg)");
|
||||
if (filename.isNull())
|
||||
return;
|
||||
|
||||
// *********
|
||||
// *******
|
||||
// *****
|
||||
// ***
|
||||
// *
|
||||
QPixmap image = ImageCropperDialog::getCroppedImage(filename, 600, 400, CropperShape::CIRCLE);
|
||||
if (image.isNull())
|
||||
return;
|
||||
|
||||
QDialog* dialog = new QDialog(0);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
QLabel* label = new QLabel(dialog);
|
||||
label->setFixedSize(image.size());
|
||||
label->setPixmap(image);
|
||||
dialog->exec();
|
||||
}
|
||||
26
netfriend/imagecropper/example/mainwindow.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QPushButton>
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
public slots:
|
||||
void onCustomCrop();
|
||||
void onSimpleCrop();
|
||||
|
||||
private:
|
||||
void setupLayout();
|
||||
|
||||
private:
|
||||
QPushButton* btnCustomCrop;
|
||||
QPushButton* btnSimpleCrop;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
20
netfriend/imagecropper/imagecropper.pro
Normal file
@@ -0,0 +1,20 @@
|
||||
QT += core gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
|
||||
|
||||
TEMPLATE = app
|
||||
DESTDIR = $$PWD/../bin
|
||||
CONFIG += warn_off
|
||||
CONFIG += c++11
|
||||
|
||||
SOURCES += \
|
||||
base/imagecropperlabel.cpp \
|
||||
example/imagecropperdemo.cpp \
|
||||
example/main.cpp \
|
||||
example/mainwindow.cpp
|
||||
|
||||
HEADERS += \
|
||||
base/imagecropperdialog.h \
|
||||
base/imagecropperlabel.h \
|
||||
example/imagecropperdemo.h \
|
||||
example/mainwindow.h
|
||||
BIN
netfriend/imagecropper/res/color-palette.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
netfriend/imagecropper/res/save.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
netfriend/imagecropper/res/select-file.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
netfriend/imageviewwindow/Resources/1.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
netfriend/imageviewwindow/Resources/2.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
netfriend/imageviewwindow/Resources/3.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
netfriend/imageviewwindow/Resources/4.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
netfriend/imageviewwindow/Resources/5.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
netfriend/imageviewwindow/Resources/6.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
netfriend/imageviewwindow/Resources/7.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
netfriend/imageviewwindow/Resources/Wblog_left.png
Normal file
|
After Width: | Height: | Size: 332 B |
BIN
netfriend/imageviewwindow/Resources/Wblog_right.png
Normal file
|
After Width: | Height: | Size: 349 B |
59
netfriend/imageviewwindow/graphicspixmap.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "graphicspixmap.h"
|
||||
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QCursor>
|
||||
#include <QDebug>
|
||||
|
||||
GraphicsPixmap::GraphicsPixmap() : QGraphicsObject()
|
||||
{
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
}
|
||||
|
||||
void GraphicsPixmap::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
QGraphicsObject::mousePressEvent(event);
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
emit clicked();
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsPixmap::setItemOffset(QPointF ponit)
|
||||
{
|
||||
prepareGeometryChange();
|
||||
offset = ponit;
|
||||
update();
|
||||
}
|
||||
|
||||
QPointF GraphicsPixmap::itemoffset()
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
void GraphicsPixmap::setPixmap(const QPixmap& pixmap)
|
||||
{
|
||||
pixSize = pixmap.size();
|
||||
pix = pixmap;
|
||||
}
|
||||
|
||||
void GraphicsPixmap::setPixmapSize(QSize size)
|
||||
{
|
||||
pixSize = size;
|
||||
}
|
||||
|
||||
QSize GraphicsPixmap::pixsize()
|
||||
{
|
||||
return pixSize;
|
||||
}
|
||||
|
||||
QRectF GraphicsPixmap::boundingRect() const
|
||||
{
|
||||
return QRectF(offset, pix.size() / pix.devicePixelRatio());
|
||||
}
|
||||
|
||||
void GraphicsPixmap::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
|
||||
{
|
||||
painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||
painter->drawPixmap(offset, pix.scaled(pixSize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
}
|
||||
38
netfriend/imageviewwindow/graphicspixmap.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef GRAPHICSPIXMAP_H
|
||||
#define GRAPHICSPIXMAP_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QGraphicsObject>
|
||||
#include <QPixmap>
|
||||
|
||||
class GraphicsPixmap : public QGraphicsObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QPointF itemoffset READ itemoffset WRITE setItemOffset)
|
||||
Q_PROPERTY(QSize itemsize READ pixsize WRITE setPixmapSize)
|
||||
|
||||
public:
|
||||
GraphicsPixmap();
|
||||
|
||||
public:
|
||||
QRectF boundingRect() const Q_DECL_OVERRIDE;
|
||||
void setItemOffset(QPointF ponit);
|
||||
QPointF itemoffset();
|
||||
QSize pixsize();
|
||||
void setPixmap(const QPixmap& pixmap);
|
||||
void setPixmapSize(QSize size);
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
|
||||
private:
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE;
|
||||
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
QPixmap pix;
|
||||
QPointF offset;
|
||||
QSize pixSize;
|
||||
};
|
||||
|
||||
#endif // GRAPHICSPIXMAP_H
|
||||
18
netfriend/imageviewwindow/graphicsview.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "graphicsview.h"
|
||||
|
||||
GraphicsView::GraphicsView(QGraphicsScene *scene)
|
||||
: QGraphicsView(scene)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
GraphicsView::~GraphicsView()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GraphicsView::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QGraphicsView::resizeEvent(event);
|
||||
fitInView(sceneRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
18
netfriend/imageviewwindow/graphicsview.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef GRAPHICSVIEW_H
|
||||
#define GRAPHICSVIEW_H
|
||||
|
||||
#include <QGraphicsView>
|
||||
|
||||
class GraphicsView : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GraphicsView(QGraphicsScene *scene);
|
||||
~GraphicsView();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
#endif // GRAPHICSVIEW_H
|
||||
211
netfriend/imageviewwindow/imageviewwindow.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
#include "imageviewwindow.h"
|
||||
#include "graphicsview.h"
|
||||
#include "graphicspixmap.h"
|
||||
|
||||
#include <QParallelAnimationGroup>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
|
||||
const int image_conunt = 5;
|
||||
const int image_yoffset = 40;
|
||||
const int image_xoffset = 60;
|
||||
ImageViewWindow::ImageViewWindow(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_isStart(false)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
initControl();
|
||||
}
|
||||
|
||||
ImageViewWindow::~ImageViewWindow()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ImageViewWindow::initControl()
|
||||
{
|
||||
//场景
|
||||
m_scene = new QGraphicsScene(QRect(0, 0, 876, 368), this);
|
||||
//图片信息
|
||||
m_imgMapInfolst << QMap<QString, QString>{
|
||||
{ "zIndex" , "1" },
|
||||
{ "width" , "120" },
|
||||
{ "height" , "150" },
|
||||
{ "top" , "71" },
|
||||
{ "left" , "134" },
|
||||
{ "opacity" , "0.6" }
|
||||
};
|
||||
m_imgMapInfolst << QMap<QString, QString>{
|
||||
{ "zIndex", "2" },
|
||||
{ "width", "130" },
|
||||
{ "height", "170" },
|
||||
{ "top", "61" },
|
||||
{ "left", "0" },
|
||||
{ "opacity", "0.7" }
|
||||
};
|
||||
m_imgMapInfolst << QMap<QString, QString>{
|
||||
{ "zIndex", "3" },
|
||||
{ "width", "170" },
|
||||
{ "height", "218" },
|
||||
{ "top", "37" },
|
||||
{ "left", "110" },
|
||||
{ "opacity", "0.8" }
|
||||
};
|
||||
m_imgMapInfolst << QMap<QString, QString>{
|
||||
{ "zIndex", "4" },
|
||||
{ "width", "224" },
|
||||
{ "height", "288" },
|
||||
{ "top", "0" },
|
||||
{ "left", "262" },
|
||||
{ "opacity", "1" }
|
||||
};
|
||||
m_imgMapInfolst << QMap<QString, QString>{
|
||||
{ "zIndex", "3" },
|
||||
{ "width", "170" },
|
||||
{ "height", "218" },
|
||||
{ "top", "37" },
|
||||
{ "left", "468" },
|
||||
{ "opacity", "0.8" }
|
||||
};
|
||||
m_imgMapInfolst << QMap<QString, QString>{
|
||||
{ "zIndex", "2" },
|
||||
{ "width", "130" },
|
||||
{ "height", "170" },
|
||||
{ "top", "61" },
|
||||
{ "left", "620" },
|
||||
{ "opacity", "0.7" }
|
||||
};
|
||||
m_imgMapInfolst << QMap<QString, QString>{
|
||||
{ "zIndex", "1" },
|
||||
{ "width", "120" },
|
||||
{ "height", "150" },
|
||||
{ "top", "71" },
|
||||
{ "left", "496" },
|
||||
{ "opacity", "0.6" }
|
||||
};
|
||||
|
||||
//场景中添加图片元素
|
||||
for (int index = 0; index < m_imgMapInfolst.size(); index++)
|
||||
{
|
||||
const auto imageInfoMap = m_imgMapInfolst[index];
|
||||
const QString&& centerImg = QString(":/ImageViewWindow/Resources/%1.jpg").arg(index + 1);
|
||||
const QPixmap&& pixmap = QPixmap(centerImg);
|
||||
GraphicsPixmap *item = new GraphicsPixmap();
|
||||
item->setPixmap(pixmap);
|
||||
item->setPixmapSize(QSize(imageInfoMap["width"].toInt(), imageInfoMap["height"].toInt()));
|
||||
item->setItemOffset(QPointF(imageInfoMap["left"].toInt() + image_xoffset, imageInfoMap["top"].toInt() + image_yoffset));
|
||||
item->setZValue(imageInfoMap["zIndex"].toInt());
|
||||
item->setOpacity(imageInfoMap["opacity"].toFloat());
|
||||
m_items << item;
|
||||
m_scene->addItem(item);
|
||||
}
|
||||
|
||||
//left button
|
||||
GraphicsPixmap *leftBtn = new GraphicsPixmap();
|
||||
leftBtn->setCursor(QCursor(Qt::PointingHandCursor));
|
||||
leftBtn->setPixmap(QPixmap(":/ImageViewWindow/Resources/Wblog_left.png"));
|
||||
leftBtn->setItemOffset(QPointF(12, image_yoffset + 124));
|
||||
leftBtn->setZValue(5);
|
||||
m_scene->addItem(leftBtn);
|
||||
connect(leftBtn, SIGNAL(clicked()), this, SLOT(onLeftBtnClicked()));
|
||||
//right button
|
||||
GraphicsPixmap *rightBtn = new GraphicsPixmap();
|
||||
rightBtn->setCursor(QCursor(Qt::PointingHandCursor));
|
||||
rightBtn->setPixmap(QPixmap(":/ImageViewWindow/Resources/Wblog_right.png"));
|
||||
rightBtn->setItemOffset(QPointF(836, image_yoffset + 124));
|
||||
rightBtn->setZValue(5);
|
||||
m_scene->addItem(rightBtn);
|
||||
connect(rightBtn, SIGNAL(clicked()), this, SLOT(onRightBtnClicked()));
|
||||
|
||||
//视图
|
||||
GraphicsView *view = new GraphicsView(m_scene);
|
||||
view->setFrameShape(QFrame::NoFrame);
|
||||
view->setParent(this);
|
||||
view->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
|
||||
view->setBackgroundBrush(QColor(46, 46, 46));
|
||||
view->setCacheMode(QGraphicsView::CacheBackground);
|
||||
view->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
|
||||
ui.viewlayout->addWidget(view);
|
||||
|
||||
//动画: 大小,位置
|
||||
m_group = new QParallelAnimationGroup;
|
||||
for (int i = 0; i < m_items.count(); ++i) {
|
||||
QPropertyAnimation *anim = new QPropertyAnimation(m_items[i], "itemoffset");
|
||||
QPropertyAnimation *anims = new QPropertyAnimation(m_items[i], "itemsize");
|
||||
m_animationMap.insert(m_items[i], anim);
|
||||
m_animationsMap.insert(m_items[i], anims);
|
||||
anim->setDuration(1000);
|
||||
anims->setDuration(1000);
|
||||
anim->setEasingCurve(QEasingCurve::OutQuad);
|
||||
anims->setEasingCurve(QEasingCurve::OutQuad);
|
||||
m_group->addAnimation(anim);
|
||||
m_group->addAnimation(anims);
|
||||
}
|
||||
//定时切换图片
|
||||
m_timer = new QTimer(this);
|
||||
m_timer->setInterval(2000);
|
||||
connect(m_timer, &QTimer::timeout, [this](){
|
||||
nextPlay();
|
||||
});
|
||||
connect(m_group, &QParallelAnimationGroup::finished, [this](){
|
||||
m_isStart = false;
|
||||
m_timer->start();
|
||||
});
|
||||
m_timer->start();
|
||||
}
|
||||
|
||||
void ImageViewWindow::onLeftBtnClicked()
|
||||
{
|
||||
//鼠标点击的时候,先暂停定时器预览
|
||||
m_timer->stop();
|
||||
//上一张
|
||||
lastPlay();
|
||||
}
|
||||
|
||||
void ImageViewWindow::onRightBtnClicked()
|
||||
{
|
||||
//鼠标点击的时候,先暂停定时器预览
|
||||
m_timer->stop();
|
||||
//下一张
|
||||
nextPlay();
|
||||
}
|
||||
|
||||
void ImageViewWindow::play()
|
||||
{
|
||||
for (int index = 0; index < m_imgMapInfolst.size(); index++)
|
||||
{
|
||||
const auto item = m_items[index];
|
||||
QPropertyAnimation *anim = m_animationMap.value(item);
|
||||
QPropertyAnimation *anims = m_animationsMap.value(item);
|
||||
const auto imageInfoMap = m_imgMapInfolst[index];
|
||||
item->setZValue(imageInfoMap["zIndex"].toInt());
|
||||
item->setOpacity(imageInfoMap["opacity"].toFloat());
|
||||
QPointF pointf(imageInfoMap["left"].toInt() + image_xoffset, imageInfoMap["top"].toInt() + image_yoffset);
|
||||
const QString&& centerImg = QString(":/ImageViewWindow/Resources/%1.jpg").arg(index + 1);
|
||||
anim->setStartValue(item->itemoffset());
|
||||
anims->setStartValue(item->pixsize());
|
||||
anim->setEndValue(pointf);
|
||||
anims->setEndValue(QSize(imageInfoMap["width"].toInt(), imageInfoMap["height"].toInt()));
|
||||
}
|
||||
m_isStart = true;
|
||||
}
|
||||
|
||||
|
||||
void ImageViewWindow::nextPlay()
|
||||
{
|
||||
m_group->stop();
|
||||
auto firstItem = m_items.takeAt(0);
|
||||
m_items << firstItem;
|
||||
play();
|
||||
m_group->start();
|
||||
}
|
||||
|
||||
void ImageViewWindow::lastPlay()
|
||||
{
|
||||
m_group->stop();
|
||||
auto lastItem = m_items.takeAt(m_items.size() - 1);
|
||||
m_items.prepend(lastItem);
|
||||
play();
|
||||
m_group->start();
|
||||
}
|
||||
42
netfriend/imageviewwindow/imageviewwindow.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef IMAGEVIEWWINDOW_H
|
||||
#define IMAGEVIEWWINDOW_H
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include "ui_imageviewwindow.h"
|
||||
|
||||
class QTimer;
|
||||
class QPropertyAnimation;
|
||||
class GraphicsPixmap;
|
||||
class QGraphicsScene;
|
||||
class QParallelAnimationGroup;
|
||||
class ImageViewWindow : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ImageViewWindow(QWidget *parent = 0);
|
||||
~ImageViewWindow();
|
||||
|
||||
private:
|
||||
void initControl();
|
||||
void nextPlay();
|
||||
void lastPlay();
|
||||
void play();
|
||||
|
||||
private slots:
|
||||
void onLeftBtnClicked();
|
||||
void onRightBtnClicked();
|
||||
|
||||
private:
|
||||
Ui::ImageViewWindowClass ui;
|
||||
QGraphicsScene* m_scene;
|
||||
QList<QMap<QString, QString> > m_imgMapInfolst;
|
||||
QList<GraphicsPixmap *> m_items;
|
||||
QParallelAnimationGroup *m_group;
|
||||
QMap<GraphicsPixmap *, QPropertyAnimation *> m_animationMap;
|
||||
QMap<GraphicsPixmap *, QPropertyAnimation *> m_animationsMap;
|
||||
QTimer* m_timer;
|
||||
bool m_isStart;
|
||||
};
|
||||
|
||||
#endif // IMAGEVIEWWINDOW_H
|
||||
20
netfriend/imageviewwindow/imageviewwindow.pro
Normal file
@@ -0,0 +1,20 @@
|
||||
QT += core gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
|
||||
|
||||
TARGET = imageviewwindow
|
||||
TEMPLATE = app
|
||||
DESTDIR = $$PWD/../bin
|
||||
CONFIG += warn_off
|
||||
|
||||
HEADERS += graphicsview.h
|
||||
HEADERS += graphicspixmap.h
|
||||
HEADERS += imageviewwindow.h
|
||||
|
||||
SOURCES += main.cpp
|
||||
SOURCES += graphicspixmap.cpp
|
||||
SOURCES += graphicsview.cpp
|
||||
SOURCES += imageviewwindow.cpp
|
||||
|
||||
FORMS += imageviewwindow.ui
|
||||
RESOURCES += imageviewwindow.qrc
|
||||
13
netfriend/imageviewwindow/imageviewwindow.qrc
Normal file
@@ -0,0 +1,13 @@
|
||||
<RCC>
|
||||
<qresource prefix="/ImageViewWindow">
|
||||
<file>Resources/1.jpg</file>
|
||||
<file>Resources/2.jpg</file>
|
||||
<file>Resources/3.jpg</file>
|
||||
<file>Resources/4.jpg</file>
|
||||
<file>Resources/5.jpg</file>
|
||||
<file>Resources/6.jpg</file>
|
||||
<file>Resources/7.jpg</file>
|
||||
<file>Resources/Wblog_left.png</file>
|
||||
<file>Resources/Wblog_right.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
39
netfriend/imageviewwindow/imageviewwindow.ui
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ImageViewWindowClass</class>
|
||||
<widget class="QWidget" name="ImageViewWindowClass">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1062</width>
|
||||
<height>538</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>ImageViewWindow</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="viewlayout">
|
||||
<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>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
<include location="imageviewwindow.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
29
netfriend/imageviewwindow/main.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "imageviewwindow.h"
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QTextCodec>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
a.setFont(QFont("Microsoft Yahei", 9));
|
||||
|
||||
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
|
||||
#if _MSC_VER
|
||||
QTextCodec *codec = QTextCodec::codecForName("gbk");
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
#endif
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
QTextCodec::setCodecForCStrings(codec);
|
||||
QTextCodec::setCodecForTr(codec);
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
#endif
|
||||
|
||||
ImageViewWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
5
netfriend/netfriend.pro
Normal file
@@ -0,0 +1,5 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += astackwidget
|
||||
SUBDIRS += imagecropper
|
||||
SUBDIRS += imageviewwindow
|
||||
SUBDIRS += slidepuzzlewidget
|
||||
BIN
netfriend/slidepuzzlewidget/Resources/back1.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
netfriend/slidepuzzlewidget/Resources/back2.png
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
netfriend/slidepuzzlewidget/Resources/back3.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
netfriend/slidepuzzlewidget/Resources/back4.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
18
netfriend/slidepuzzlewidget/frmslidepuzzlewidget.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "frmslidepuzzlewidget.h"
|
||||
|
||||
FrmSlidePuzzleWidget::FrmSlidePuzzleWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
this->initForm();
|
||||
}
|
||||
|
||||
FrmSlidePuzzleWidget::~FrmSlidePuzzleWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FrmSlidePuzzleWidget::initForm()
|
||||
{
|
||||
|
||||
}
|
||||
22
netfriend/slidepuzzlewidget/frmslidepuzzlewidget.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef FRMSLIDEPUZZLEWIDGET_H
|
||||
#define FRMSLIDEPUZZLEWIDGET_H
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include "ui_frmslidepuzzlewidget.h"
|
||||
|
||||
class FrmSlidePuzzleWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FrmSlidePuzzleWidget(QWidget *parent = 0);
|
||||
~FrmSlidePuzzleWidget();
|
||||
|
||||
private:
|
||||
void initForm();
|
||||
|
||||
private:
|
||||
Ui::FrmSlidePuzzleWidgetClass ui;
|
||||
};
|
||||
|
||||
#endif // FRMSLIDEPUZZLEWIDGET_H
|
||||
8
netfriend/slidepuzzlewidget/frmslidepuzzlewidget.qrc
Normal file
@@ -0,0 +1,8 @@
|
||||
<RCC>
|
||||
<qresource prefix="/FrmSlidePuzzleWidget">
|
||||
<file>Resources/back1.png</file>
|
||||
<file>Resources/back2.png</file>
|
||||
<file>Resources/back3.png</file>
|
||||
<file>Resources/back4.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
50
netfriend/slidepuzzlewidget/frmslidepuzzlewidget.ui
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FrmSlidePuzzleWidgetClass</class>
|
||||
<widget class="QWidget" name="FrmSlidePuzzleWidgetClass">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>FrmSlidePuzzleWidget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="SliderPuzzleWidget" name="sliderpuzzleWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>SliderPuzzleWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>sliderpuzzlewidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="frmslidepuzzlewidget.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
30
netfriend/slidepuzzlewidget/main.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "frmslidepuzzlewidget.h"
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
a.setFont(QFont("Microsoft Yahei", 10));
|
||||
|
||||
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
|
||||
#if _MSC_VER
|
||||
QTextCodec *codec = QTextCodec::codecForName("gbk");
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
#endif
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
QTextCodec::setCodecForCStrings(codec);
|
||||
QTextCodec::setCodecForTr(codec);
|
||||
#else
|
||||
QTextCodec *codec = QTextCodec::codecForName("utf-8");
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
#endif
|
||||
|
||||
FrmSlidePuzzleWidget w;
|
||||
w.setWindowTitle("滑块图片验证码");
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
81
netfriend/slidepuzzlewidget/puzzlewidget.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#include "puzzlewidget.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QTime>
|
||||
#include <QTimer>
|
||||
|
||||
const int squarewidth = 46;
|
||||
const int squareradius = 20;
|
||||
PuzzleWidget::PuzzleWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_value = 0;
|
||||
m_offsetPoint = QPoint(0, 0);
|
||||
srand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
|
||||
}
|
||||
|
||||
PuzzleWidget::~PuzzleWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PuzzleWidget::setPixmap(const QString& pixmap)
|
||||
{
|
||||
m_pixmap = pixmap;
|
||||
QTimer::singleShot(10, this, SLOT(onUpdatePixmap()));
|
||||
}
|
||||
|
||||
void PuzzleWidget::onUpdatePixmap()
|
||||
{
|
||||
m_offsetPoint.rx() = qBound(0, rand() % this->width() + squarewidth + squareradius, this->width() - squarewidth - squareradius);
|
||||
m_offsetPoint.ry() = qBound(0, rand() % this->height() + squarewidth + squareradius, this->height() - squarewidth - squareradius);
|
||||
update();
|
||||
}
|
||||
|
||||
void PuzzleWidget::setValue(int value)
|
||||
{
|
||||
m_value = qBound(0, value, this->width() - squarewidth - squareradius + m_offsetPoint.x());
|
||||
update();
|
||||
}
|
||||
|
||||
void PuzzleWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.setRenderHints(QPainter::Antialiasing);
|
||||
QPainterPath clippath;
|
||||
clippath.addRoundedRect(this->rect(), 4, 4);
|
||||
painter.setClipPath(clippath);
|
||||
const QPixmap& pixmap = QPixmap(m_pixmap).scaled(this->width(), this->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
painter.drawPixmap(0, 0, this->width(), this->height(), pixmap);
|
||||
|
||||
QPainterPath cutoutpath;
|
||||
cutoutpath.setFillRule(Qt::WindingFill);
|
||||
QRect rect(m_offsetPoint, QSize(squarewidth, squarewidth));
|
||||
cutoutpath.addRoundedRect(rect, 2, 2);
|
||||
cutoutpath.addEllipse(rect.center().x() - squareradius / 2, rect.top() - squareradius + 6, squareradius, squareradius);
|
||||
QPainterPath subellipseparh;
|
||||
subellipseparh.addEllipse(rect.right() - squareradius + 6, rect.center().y() - squareradius / 2, squareradius, squareradius);
|
||||
cutoutpath -= subellipseparh;
|
||||
|
||||
painter.setPen(QPen(QColor(80, 80, 80), 1));
|
||||
painter.setBrush(QColor(100, 100, 100, 220));
|
||||
painter.drawPath(cutoutpath);
|
||||
|
||||
QPixmap puzzlePixmap(this->size());
|
||||
puzzlePixmap.fill(Qt::transparent);
|
||||
QPainter puzzlePainter(&puzzlePixmap);
|
||||
puzzlePainter.setRenderHints(QPainter::Antialiasing);
|
||||
puzzlePainter.setClipPath(cutoutpath);
|
||||
puzzlePainter.setPen(QPen(QColor(80, 80, 80), 2));
|
||||
puzzlePainter.setBrush(QColor(200, 200, 200, 100));
|
||||
puzzlePainter.drawPixmap(0, 0, this->width(), this->height(), pixmap);
|
||||
puzzlePainter.drawPath(cutoutpath);
|
||||
|
||||
painter.drawPixmap(-m_offsetPoint.x() + m_value, 0, this->width(), this->height(), puzzlePixmap);
|
||||
}
|
||||
|
||||
bool PuzzleWidget::isOverlap()
|
||||
{
|
||||
return qAbs(-m_offsetPoint.x() + m_value) < 5;
|
||||
}
|
||||
34
netfriend/slidepuzzlewidget/puzzlewidget.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef PUZZLEWIDGET_H
|
||||
#define PUZZLEWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class PuzzleWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString pixmap READ getPixmap WRITE setPixmap)
|
||||
|
||||
public:
|
||||
PuzzleWidget(QWidget *parent);
|
||||
~PuzzleWidget();
|
||||
|
||||
public:
|
||||
QString getPixmap() const { return m_pixmap; };
|
||||
void setPixmap(const QString& pixmap);
|
||||
|
||||
void setValue(int value);
|
||||
bool isOverlap();
|
||||
|
||||
private slots:
|
||||
void onUpdatePixmap();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
|
||||
private:
|
||||
int m_value;
|
||||
QString m_pixmap;
|
||||
QPoint m_offsetPoint;
|
||||
};
|
||||
|
||||
#endif // PUZZLEWIDGET_H
|
||||
23
netfriend/slidepuzzlewidget/slidepuzzlewidget.pro
Normal file
@@ -0,0 +1,23 @@
|
||||
QT += core gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
|
||||
|
||||
TEMPLATE = app
|
||||
TARGET = slidepuzzlewidget
|
||||
DESTDIR = $$PWD/../bin
|
||||
CONFIG += warn_off
|
||||
|
||||
HEADERS += frmslidepuzzlewidget.h
|
||||
HEADERS += puzzlewidget.h
|
||||
HEADERS += sliderpuzzlewidget.h
|
||||
|
||||
SOURCES += main.cpp
|
||||
SOURCES += frmslidepuzzlewidget.cpp
|
||||
SOURCES += puzzlewidget.cpp
|
||||
SOURCES += sliderpuzzlewidget.cpp
|
||||
|
||||
FORMS += frmslidepuzzlewidget.ui
|
||||
FORMS += sliderpuzzlewidget.ui
|
||||
RESOURCES += frmslidepuzzlewidget.qrc
|
||||
|
||||
|
||||
49
netfriend/slidepuzzlewidget/sliderpuzzlewidget.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
#include "sliderpuzzlewidget.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
|
||||
SliderPuzzleWidget::SliderPuzzleWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
this->initForm();
|
||||
}
|
||||
|
||||
SliderPuzzleWidget::~SliderPuzzleWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SliderPuzzleWidget::initForm()
|
||||
{
|
||||
QTimer::singleShot(10, this, SLOT(onUpdateWidget()));
|
||||
connect(ui.horizontalSlider, &QSlider::valueChanged, this, &SliderPuzzleWidget::onSliderValueChanged);
|
||||
connect(ui.horizontalSlider, &QSlider::sliderReleased, this, &SliderPuzzleWidget::onSliderReleased);
|
||||
ui.puzzlewidget->setPixmap(":/FrmSlidePuzzleWidget/Resources/back1.png");
|
||||
}
|
||||
|
||||
void SliderPuzzleWidget::onUpdateWidget()
|
||||
{
|
||||
ui.horizontalSlider->setRange(0, this->width());
|
||||
}
|
||||
|
||||
void SliderPuzzleWidget::onSliderValueChanged(int value)
|
||||
{
|
||||
ui.puzzlewidget->setValue(value);
|
||||
}
|
||||
|
||||
void SliderPuzzleWidget::onSliderReleased()
|
||||
{
|
||||
QString content = ui.puzzlewidget->isOverlap() ? "验证成功!" : "验证失败!";
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("滑块图片验证码");
|
||||
msgBox.setText(content);
|
||||
msgBox.exec();
|
||||
|
||||
static int testIndex = 1;
|
||||
testIndex = testIndex + 1 > 4 ? 1 : testIndex + 1;
|
||||
ui.horizontalSlider->setValue(0);
|
||||
ui.puzzlewidget->setPixmap(QString(":/FrmSlidePuzzleWidget/Resources/back%1.png").arg(testIndex));
|
||||
}
|
||||
27
netfriend/slidepuzzlewidget/sliderpuzzlewidget.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef SLIDERPUZZLEWIDGET_H
|
||||
#define SLIDERPUZZLEWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "ui_sliderpuzzlewidget.h"
|
||||
|
||||
class SliderPuzzleWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SliderPuzzleWidget(QWidget *parent = 0);
|
||||
~SliderPuzzleWidget();
|
||||
|
||||
private:
|
||||
void initForm();
|
||||
|
||||
private slots:
|
||||
void onUpdateWidget();
|
||||
void onSliderValueChanged(int value);
|
||||
void onSliderReleased();
|
||||
|
||||
private:
|
||||
Ui::SliderPuzzleWidget ui;
|
||||
};
|
||||
|
||||
#endif // SLIDERPUZZLEWIDGET_H
|
||||
55
netfriend/slidepuzzlewidget/sliderpuzzlewidget.ui
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SliderPuzzleWidget</class>
|
||||
<widget class="QWidget" name="SliderPuzzleWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>717</width>
|
||||
<height>320</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>SliderPuzzleWidget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>14</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>
|
||||
<widget class="PuzzleWidget" name="puzzlewidget" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="horizontalSlider">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>PuzzleWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>puzzlewidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||