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;
}