Qtウィンドウの自動隠し機能実装(マルチスクリーン対応)

Qtフレームワークを使用したウィンドウの自動隠し機能について解説します。この機能はウィンドウが画面端に接触した際に自動的に隠れ、マウスホバーで再表示される動作を実現します。

ウィンドウドラッグ処理

ウィンドウ移動機能を実装するには以下の3つのイベントハンドラをオーバーライドします。

マウス押下イベント

void AutoHideWindow::mousePressEvent(QMouseEvent* event)
{
    if (event->button() == Qt::LeftButton) {
        dragOffset = event->globalPosition().toPoint() - frameGeometry().topLeft();
        event->accept();
    }
}

マウス移動イベント

void AutoHideWindow::mouseMoveEvent(QMouseEvent* event)
{
    if (event->buttons() & Qt::LeftButton) {
        QPoint newPosition = event->globalPosition().toPoint() - dragOffset;
        
        QScreen* currentScreen = QGuiApplication::screenAt(QCursor::pos());
        QRect screenRect = currentScreen->geometry();
        QRect frameRect = frameGeometry();
        
        // 画面境界制限
        if (newPosition.y() <= screenRect.top()) {
            newPosition.setY(screenRect.top());
        }
        if (newPosition.x() <= screenRect.left()) {
            newPosition.setX(screenRect.left());
        }
        if (newPosition.x() + frameRect.width() >= screenRect.right()) {
            newPosition.setX(screenRect.right() - frameRect.width());
        }
        
        move(newPosition);
        event->accept();
    }
}

マウスリリースイベント

void AutoHideWindow::mouseReleaseEvent(QMouseEvent* event)
{
    QWidget::mouseReleaseEvent(event);
}

自動隠し機能の実装

ウィンドウの境界検出と自動隠し/表示のメカニズムを実装します。

マウス離脱イベント

void AutoHideWindow::leaveEvent(QEvent* event)
{
    QPoint cursorPos = mapFromGlobal(QCursor::pos());
    
    if (!rect().contains(cursorPos)) {
        hideWindow();
    } else {
        if (!hideTimer) {
            hideTimer = new QTimer(this);
            connect(hideTimer, &QTimer::timeout, this, [this]{
                QPoint pos = mapFromGlobal(QCursor::pos());
                if (!this->rect().contains(pos)) {
                    hideWindow();
                }
            });
        }
        hideTimer->start(500);
    }
    QWidget::leaveEvent(event);
}

マウス進入イベント

void AutoHideWindow::enterEvent(QEnterEvent* event)
{
    if (hideTimer && hideTimer->isActive()) {
        hideTimer->stop();
    }
    showWindow();
    QWidget::enterEvent(event);
}

ウィンドウ隠蔽処理

void AutoHideWindow::hideWindow()
{
    if (!isVisible) return;
    isVisible = false;

    QScreen* screen = QGuiApplication::screenAt(pos());
    QRect screenGeometry = screen->geometry();
    
    const int hideWidth = width() - HIDE_OFFSET;
    const int hideHeight = height() - HIDE_OFFSET;
    
    if (frameGeometry().left() <= BORDER_THRESHOLD && (features & LEFT_EDGE)) {
        slideWindow(pos(), pos() - QPoint(hideWidth, 0));
    } else if (frameGeometry().right() >= screenGeometry.right() - BORDER_THRESHOLD && (features & RIGHT_EDGE)) {
        slideWindow(pos(), pos() + QPoint(hideWidth, 0));
    } else if (frameGeometry().top() <= BORDER_THRESHOLD && (features & TOP_EDGE)) {
        slideWindow(pos(), pos() - QPoint(0, hideHeight));
    } else {
        isVisible = true;
    }
}

ウィンドウ表示処理

void AutoHideWindow::showWindow()
{
    if (isVisible) return;
    isVisible = true;
    
    const int revealWidth = width() - HIDE_OFFSET;
    const int revealHeight = height() - HIDE_OFFSET;
    
    if (frameGeometry().left() == storedPosition.x() - revealWidth && (features & LEFT_EDGE)) {
        slideWindow(pos(), storedPosition);
    } else if (frameGeometry().left() == storedPosition.x() + revealWidth && (features & RIGHT_EDGE)) {
        slideWindow(pos(), storedPosition);
    } else if (frameGeometry().top() == storedPosition.y() - revealHeight && (features & TOP_EDGE)) {
        slideWindow(pos(), storedPosition);
    } else {
        isVisible = false;
    }
}

アニメーション移動

void AutoHideWindow::slideWindow(const QPoint& start, const QPoint& end, int stepSize)
{
    QPoint delta = end - start;
    QPoint stepVector;
    
    if (delta.x() == 0) {
        stepVector.setY(stepSize * (delta.y() > 0 ? 1 : -1));
    } else {
        stepVector.setX(stepSize * (delta.x() > 0 ? 1 : -1));
    }
    
    int totalSteps = abs(delta.manhattanLength() / stepSize);
    for (int i = 0; i < totalSteps; ++i) {
        move(start + stepVector * i);
        QCoreApplication::processEvents();
    }
    move(end);
    storedPosition = start;
}

タグ: Qt ウィンドウ管理 マルチスクリーン 自動隠し C++

7月3日 16:43 投稿