#include "pagetotalpay.h" #include "ui_pagetotalpay.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include PageTotalPay::PageTotalPay(QWidget *parent) : QWidget(parent) , ui(new Ui::PageTotalPay) { ui->setupUi(this); if (objectName().isEmpty()) setObjectName("PageTotalPay"); // ✅ 여기 추가 setStyleSheet("QWidget#PageTotalPay { background-color: rgb(34,197,94); }"); // ✅ Scene/View m_scene = new QGraphicsScene(this); m_view = new QGraphicsView(this); m_view->setScene(m_scene); m_view->setFrameShape(QFrame::NoFrame); m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_view->setStyleSheet("background: transparent;"); m_view->setAlignment(Qt::AlignCenter); // 클릭 이벤트를 view/viewport에서도 잡기 m_view->viewport()->installEventFilter(this); m_view->installEventFilter(this); // ✅ content 위젯(아이콘+텍스트) m_content = new QWidget(); m_content->setAttribute(Qt::WA_TranslucentBackground); m_content->installEventFilter(this); auto *lay = new QVBoxLayout(m_content); lay->setContentsMargins(0, 0, 0, 0); lay->setSpacing(28); lay->setAlignment(Qt::AlignCenter); QLabel *lblIcon = new QLabel(m_content); lblIcon->setFixedSize(140, 140); lblIcon->setAlignment(Qt::AlignCenter); lblIcon->setPixmap(makeCheckIcon(128)); lblIcon->setStyleSheet("background: transparent;"); QLabel *lblTitle = new QLabel("구매해주셔서 감사합니다", m_content); lblTitle->setAlignment(Qt::AlignCenter); lblTitle->setStyleSheet( "background: transparent;" "color: rgb(0,0,0);" "font-weight: 900;" "font-size: 44px;" ); QLabel *lblSub = new QLabel("화면을 다시 눌러 시작하기", m_content); lblSub->setAlignment(Qt::AlignCenter); lblSub->setStyleSheet( "background: transparent;" "color: rgb(0,0,0);" "font-weight: 700;" "font-size: 22px;" ); lay->addWidget(lblIcon, 0, Qt::AlignCenter); lay->addWidget(lblTitle, 0, Qt::AlignCenter); lay->addWidget(lblSub, 0, Qt::AlignCenter); // ✅ proxy로 올리기(스케일 애니메이션 대상) m_proxy = m_scene->addWidget(m_content); m_proxy->setTransformOriginPoint(m_proxy->boundingRect().center()); // ✅ 레이아웃 붙이기 (중요: 기존 레이아웃 있으면 거기에 붙임) if (this->layout()) { this->layout()->setContentsMargins(0,0,0,0); this->layout()->addWidget(m_view); } else { auto *root = new QVBoxLayout(this); root->setContentsMargins(0,0,0,0); root->addWidget(m_view); } // ✅❗️여기가 너 코드에서 크래시 난 부분: m_pulseAnim을 반드시 생성해야 함 m_pulseAnim = new QVariantAnimation(this); // ✅ 코사인 루프 (자연스럽게 1.0 -> 1.15 -> 1.0, 점프 없음) m_pulseAnim->setStartValue(0.0); m_pulseAnim->setEndValue(2.0 * M_PI); m_pulseAnim->setDuration(2000); m_pulseAnim->setLoopCount(-1); m_pulseAnim->setEasingCurve(QEasingCurve::Linear); connect(m_pulseAnim, &QVariantAnimation::valueChanged, this, [this](const QVariant &v){ const qreal t = v.toReal(); const qreal amp = 0.15; const qreal scale = 1.0 + amp * 0.5 * (1.0 - qCos(t)); if (m_proxy) m_proxy->setScale(scale); }); m_pulseAnim->start(); // ✅ viewport size가 0일 수 있으니 show 이후에 중앙 정렬 QTimer::singleShot(0, this, [this](){ centerProxy(); }); } PageTotalPay::~PageTotalPay() { delete ui; } QPixmap PageTotalPay::makeCheckIcon(int sizePx) const { const int pad = 6; QPixmap pm(sizePx + pad*2, sizePx + pad*2); pm.fill(Qt::transparent); QPainter p(&pm); p.setRenderHint(QPainter::Antialiasing, true); // ✅ 초록색 (Tailwind green-500 비슷) QColor green(34, 197, 94); // circle stroke QPen pen(green); // ✅ 여기! pen.setWidthF(sizePx * 0.07); pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); p.setPen(pen); p.setBrush(Qt::NoBrush); QRectF rc(pad, pad, sizePx, sizePx); p.drawEllipse(rc); // check p.setPen(Qt::NoPen); p.setBrush(green); p.drawEllipse(rc); // 체크: 흰색 QPen pen2(Qt::white); pen2.setWidthF(sizePx * 0.09); pen2.setCapStyle(Qt::RoundCap); pen2.setJoinStyle(Qt::RoundJoin); p.setPen(pen2); p.setBrush(Qt::NoBrush); QPointF a(rc.left() + sizePx*0.28, rc.top() + sizePx*0.55); QPointF b(rc.left() + sizePx*0.46, rc.top() + sizePx*0.70); QPointF c(rc.left() + sizePx*0.74, rc.top() + sizePx*0.36); p.drawLine(a, b); p.drawLine(b, c); return pm; } void PageTotalPay::centerProxy() { if (!m_view || !m_scene || !m_proxy) return; const QSize vsz = m_view->viewport()->size(); if (vsz.width() <= 0 || vsz.height() <= 0) return; // ✅ 0이면 아직 표시 전 m_scene->setSceneRect(0, 0, vsz.width(), vsz.height()); const QPointF origin = m_proxy->boundingRect().center(); m_proxy->setTransformOriginPoint(origin); const QPointF sceneCenter = m_scene->sceneRect().center(); m_proxy->setPos(sceneCenter - origin); } void PageTotalPay::resizeEvent(QResizeEvent *e) { QWidget::resizeEvent(e); centerProxy(); } bool PageTotalPay::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::MouseButtonPress) { emit backToStartClicked(); return true; } return QWidget::eventFilter(obj, event); } void PageTotalPay::mousePressEvent(QMouseEvent *e) { emit backToStartClicked(); QWidget::mousePressEvent(e); }