#include "maskoverlay.h" #include #include #include #include #include #include #include #include "qdebug.h" MaskOverlay* MaskOverlay::instance_ = nullptr; MaskOverlay* MaskOverlay::instance() { if (!instance_) { instance_ = new MaskOverlay(qApp); } return instance_; } MaskOverlay::MaskOverlay(QObject* parent) : QObject(parent) , globalStyle_("background-color: rgba(0, 0, 0, 128);") , progressStyle_("QProgressBar {" " border: 2px solid #555;" " border-radius: 5px;" " background: rgba(255, 255, 255, 150);" "}" "QProgressBar::chunk {" " background-color: #05B8CC;" " border-radius: 3px;" "}") {} QWidget* MaskOverlay::findBestTarget(QWidget* hintTarget, FindMode mode) { if (hintTarget) return hintTarget; switch (mode) { case ActiveWindow: return QApplication::activeWindow(); case MainWindow: { foreach (QWidget* w, QApplication::topLevelWidgets()) { if (w->isWindow() && w->windowType() == Qt::Window) { return w; } } return nullptr; } case ParentWindow: return qobject_cast(parent()); default: return nullptr; } } void MaskOverlay::show(QWidget* target, int timeoutMs, FindMode findMode, std::function timeoutCallback) { QWidget* actualTarget = findBestTarget(target, findMode); if (!actualTarget) { qWarning() << "No suitable target window found"; return; } if (overlays_.contains(actualTarget)) return; setupOverlay(actualTarget); OverlayContext& ctx = overlays_[actualTarget]; // 渐显动画 QGraphicsOpacityEffect* effect = new QGraphicsOpacityEffect(ctx.maskWidget); ctx.maskWidget->setGraphicsEffect(effect); QPropertyAnimation* anim = new QPropertyAnimation(effect, "opacity"); anim->setDuration(300); anim->setStartValue(0); anim->setEndValue(1); anim->start(QPropertyAnimation::DeleteWhenStopped); ctx.maskWidget->show(); ctx.maskWidget->raise(); lastShownTarget_ = actualTarget; if (timeoutMs > 0) { ctx.timeoutTimer->setInterval(timeoutMs); ctx.timeoutTimer->start(); ctx.timeoutCallback = timeoutCallback; } } void MaskOverlay::hide(QWidget* target) { QWidget* actualTarget = target ? target : lastShownTarget_.data(); if (!actualTarget) actualTarget = findBestTarget(nullptr, ActiveWindow); if (!actualTarget || !overlays_.contains(actualTarget)) return; OverlayContext ctx = overlays_.take(actualTarget); ctx.timeoutTimer->stop(); // 渐隐动画 QGraphicsOpacityEffect* effect = new QGraphicsOpacityEffect(ctx.maskWidget); ctx.maskWidget->setGraphicsEffect(effect); QPropertyAnimation* anim = new QPropertyAnimation(effect, "opacity"); anim->setDuration(300); anim->setStartValue(1); anim->setEndValue(0); connect(anim, &QPropertyAnimation::finished, [ctx]() { ctx.maskWidget->deleteLater(); ctx.progressBar->deleteLater(); ctx.timeoutTimer->deleteLater(); }); anim->start(QPropertyAnimation::DeleteWhenStopped); } void MaskOverlay::setupOverlay(QWidget* target) { if (!target || overlays_.contains(target)) return; OverlayContext ctx; ctx.maskWidget = new QWidget(target); ctx.maskWidget->setStyleSheet(globalStyle_); ctx.maskWidget->setAttribute(Qt::WA_TransparentForMouseEvents, false); ctx.maskWidget->resize(target->size()); ctx.progressBar = new QProgressBar(ctx.maskWidget); ctx.progressBar->setStyleSheet(progressStyle_); ctx.progressBar->setRange(0, 0); ctx.progressBar->setFixedSize(200, 20); QVBoxLayout* layout = new QVBoxLayout(ctx.maskWidget); layout->addWidget(ctx.progressBar, 0, Qt::AlignCenter); ctx.timeoutTimer = new QTimer(this); ctx.timeoutTimer->setSingleShot(true); connect(ctx.timeoutTimer, &QTimer::timeout, [this, target]() { if (overlays_.contains(target)) { if (overlays_[target].timeoutCallback) { overlays_[target].timeoutCallback(); } this->hide(target); } }); target->installEventFilter(this); overlays_.insert(target, ctx); } bool MaskOverlay::eventFilter(QObject* watched, QEvent* event) { QWidget* target = qobject_cast(watched); if (!target) return false; if (event->type() == QEvent::Resize) { if (overlays_.contains(target)) { overlays_[target].maskWidget->resize(target->size()); } } else if (event->type() == QEvent::Close) { hide(target); } return QObject::eventFilter(watched, event); } void MaskOverlay::setGlobalStyle(const QString& styleSheet) { globalStyle_ = styleSheet; for (auto& ctx : overlays_) { ctx.maskWidget->setStyleSheet(globalStyle_); } } void MaskOverlay::setProgressBarStyle(const QString& styleSheet) { progressStyle_ = styleSheet; for (auto& ctx : overlays_) { ctx.progressBar->setStyleSheet(progressStyle_); } } void MaskOverlay::setProgressValue(QWidget* target, int value) { QWidget* actualTarget = target ? target : lastShownTarget_.data(); if (!actualTarget || !overlays_.contains(actualTarget)) return; OverlayContext& ctx = overlays_[actualTarget]; ctx.progressBar->setRange(0, 100); // 设置为确定模式 ctx.progressBar->setValue(value); } void MaskOverlay::setTimeout(QWidget* target, int milliseconds) { if (target && overlays_.contains(target)) { overlays_[target].timeoutTimer->setInterval(milliseconds); } }