Программно вызвать Snap / Aero развернуть

Есть ли способ программно вызвать эффект максимизации Aera, используя C или C ++ для определенного окна / идентификатора окна?

Например:

введите описание изображения здесь

или же

введите описание ссылки здесь http://www.thebuzzmedia.com/wp-content/uploads/2009/05/windows-7-aero-snap-to-edge-effect.png

Я использую окно без границ Qt, и у Qt есть API для получения идентификатора окна. Я хочу программно запускать эффекты Windows без известных триггеров.

3

Решение

Я не хочу говорить о каждой детали, связанной с достижением этого эффекта, не только многое происходит, но вы также упомянули, что понимаете логику размещения окон в их определенных местах. В этом ответе я расскажу о двух основных проблемах, которые я считаю:

  • Как получить и обработать максимизировать событие?

  • Как создать приближение аэро оснастка эффект?

Для того, чтобы ответить на первый вопрос, мы должны проанализировать, какие обработчики событий запускаются, когда окно развернуто:

void resizeEvent(QResizeEvent* evt);   // Invoked first,
void paintEvent(QPaintEvent* event);   // then second,
void changeEvent(QEvent* evt);         // and at last.

Приложение Qt сначала уведомляется о resizeEvent(), за которым следует paintEvent() нарисовать окно (или виджет), и только после того, как все было отображено, changeEvent() вызывается, чтобы вы знали, что виджет был развернут (возможно, уже немного поздно, чтобы получить такое уведомление, я не знаю).

Из всех, что нас волнует, resizeEvent(), Этот обработчик события сообщает о новом размере окна / виджета, который можно использовать для сравнения с размером рабочего стола, что позволяет нам узнать, действительно ли событие было максимизированным запросом. Как только мы определим запрос на максимизацию, мы можем выяснить, должно ли приложение быть развернуто (и привязано) к право, оставил или к центр экрана.

Это будет время для создания виджет аэроснимка и поместите его на экран в качестве визуальной подсказки для пользователя.

Ответить на второй вопрос, Я не думаю, что можно вызвать собственный API Windows и попросить его вежливо выполнить этот эффект в вашем окне. Единственный логичный выбор — написать код, который сам по себе аппроксимирует этот эффект.

Визуальный внешний вид можно воспроизвести, нарисовав прозрачное окно с рамкой тени. Подход, продемонстрированный в исходном коде ниже, создает и настраивает QWidget чтобы заставить его вести себя и выглядеть как аэро оснастка окно:

введите описание изображения здесь

Я знаю, это не самая красивая вещь в мире. Эта демонстрация создает обычное окно для взаимодействия с пользователем, и, когда оно развернуто, оно располагается слева от экрана. На правильный размер экрана он отображает что-то похожее на аэро оснастка окно (показано выше).

Идея позади виджет аэроснимка очень просто: QWidget с прозрачным фоном и пользовательской процедурой покраски. Другими словами, это прозрачное окно, которое рисует скругленный прямоугольник с тенью и все.

Чтобы сделать его более реалистичным, вы должны добавить анимацию, чтобы постепенно изменять размер виджета. for цикл может сделать свое дело, но если вам нужно что-то необычное, вы в конечном итоге использовать таймеры. Если вы берете Смотри сюда, Вы можете увидеть самый быстрый & самый грязный метод для выполнения анимации с Qt в действии, и лучшие способы борьбы с анимацией. Тем не менее, для простых задач, как это, придерживайтесь на основе кадров анимация.

main.cpp:

#include "window.h"#include <QApplication>

int main(int argc, char* argv[])
{
QApplication app(argc, argv);
Window window;
window.show();

return app.exec();
}

window.h:

#pragma once
#include "snapwindow.h"#include <QMainWindow>
#include <QEvent>

class Window : public QMainWindow
{
public:
Window();

void resizeEvent(QResizeEvent* evt);
//void paintEvent(QPaintEvent* event);
void changeEvent(QEvent* evt);

private:
SnapWindow* _sw;
};

window.cpp:

#include "window.h"#include "snapwindow.h"
#include <QDebug>
#include <QWindowStateChangeEvent>
#include <QApplication>
#include <QDesktopWidget>

Window::Window()
{
setWindowTitle("AeroSnap");
resize(300, 300);

_sw = new SnapWindow(this);
_sw->hide();
}

void Window::changeEvent(QEvent* evt)
{
if (evt->type() == QEvent::WindowStateChange)
{
QWindowStateChangeEvent* event = static_cast<QWindowStateChangeEvent*>(evt);

if (event->oldState() == Qt::WindowNoState &&
windowState() == Qt::WindowMaximized)
{
qDebug() << "changeEvent: window is now maximized!";
}
}
}

// resizeEvent is triggered before window_maximized event
void Window::resizeEvent(QResizeEvent* evt)
{
qDebug() << "resizeEvent: request to resize window to: " << evt->size();

QSize desktop_sz = QApplication::desktop()->size();
//qDebug() << "resizeEvent: desktop sz " << desktop_sz.width() << "x" << desktop_sz.height();

// Apparently, the maximum size a window can have in my system (1920x1080)
// is actually 1920x990. I suspect this happens because the taskbar has 90px of height:
desktop_sz.setHeight(desktop_sz.height() - 90);

// If this not a request to maximize the window, don't do anything crazy.
if (desktop_sz.width() != evt->size().width() ||
desktop_sz.height() != evt->size().height())
return;

// Alright, now we known it's a maximize request:
qDebug() << "resizeEvent: maximize this window to the left";

// so we update the window geometry (i.e. size and position)
// to what we think it's appropriate: half width to the left
int new_width = evt->size().width();
int new_height = evt->size().height();
int x_offset = 10;
setGeometry(x_offset, 45, new_width/2, new_height-45); // y 45 and height -45 are due to the 90px problem

/* Draw aero snap widget */

_sw->setGeometry(new_width/2-x_offset, 0, new_width/2, new_height);
_sw->show();

// paintEvent() will be called automatically after this method ends,
// and will draw this window with the appropriate geometry.
}

snapwindow.h:

#pragma once
#include <QWidget>

class SnapWindow : public QWidget
{
public:
SnapWindow(QWidget* parent = 0);

void paintEvent(QPaintEvent *event);
};

snapwindow.cpp:

#include "snapwindow.h"#include <QPainter>
#include <QGraphicsDropShadowEffect>

SnapWindow::SnapWindow(QWidget* parent)
: QWidget(parent)
{
// Set this widget as top-level (i.e. owned by user)
setParent(0);

/* Behold: the magic of creating transparent windows */

setWindowFlags(Qt::Widget | Qt::FramelessWindowHint);
setStyleSheet("background:transparent;");
setAttribute(Qt::WA_NoSystemBackground, true); // speed up drawing by removing unnecessary background initialization
setAttribute(Qt::WA_TranslucentBackground);
//setAutoFillBackground(true);

/* Use Qt tricks to paint stuff with shadows */

QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect();
effect->setBlurRadius(12);
effect->setOffset(0);
effect->setColor(QColor(0, 0, 0, 255));
setGraphicsEffect(effect);
}

void SnapWindow::paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);

/* Lazy way of painting a shadow */

QPainter painter(this);
QPen pen(QColor(180, 180, 180, 200));
pen.setWidth(3);
painter.setPen(pen);

// Offset 6 and 9 pixels so the shadow shows up properly
painter.drawRoundedRect(QRect(6, 6, (width()-1)-9, (height()-1)-9), 18, 18);
}

Это просто быстрое демо, чтобы указать вам правильное направление. Это ни в коем случае не полная реализация эффекта, который вы ищете.

4

Другие решения

Возможно, это не то, что вам нужно, но этот эффект — просто изменение размера и перемещение окна, затем попробуйте использовать методы Qt для этого.

bool left = false;
QSize size = QApplication::desktop()->size();//resolution of current screen
if(left)
{//left side
this->setGeometry(0, 0, size.width()/2, size.height());//(maybe need do some changes)
}
else
{//right side
this->setGeometry(size.width()/2, 0, size.width()/2, size.height());
}

С QApplication::desktop() он будет работать правильно на экране с разными разрешениями.

В сети я нашел что-то похожее в winapi, но это не сработало должным образом:

HWND act = GetForegroundWindow();
PostMessage((HWND)act,WM_NCLBUTTONDBLCLK, HTTOP, 0);

Лучший способ

Объедините это подходы. Например:

HWND act = GetForegroundWindow();
bool left = false;
QSize size = QApplication::desktop()->size();
if(left)
{
this->move(0,0);
PostMessage((HWND)act,WM_NCLBUTTONDBLCLK, HTTOP, 0);
this->resize(size.width()/2,QApplication::desktop()->height());

}
else
{
this->move(size.width()/2,0);
PostMessage((HWND)act,WM_NCLBUTTONDBLCLK, HTTOP, 0);
this->resize(size.width()/2,QApplication::desktop()->height());
}

Зачем? Так как move() регулировать левую и правую стороны, но PostMessage (winapi) правильно установить высоту окна на каждом экране (окно не будет располагаться ниже taskbarкак в вашем примере)

РЕДАКТИРОВАТЬ

Я немного изменил код и теперь он стал лучше. Да, он снова изменяет размер, но теперь у него нет кода winapi (PostMessage и т.д.), так что Photoshop не улавливает это, есть один интересный метод в Qt, который называется availableGeometry. Он возвращает нормальную высоту экрана, которая нам нужна, при этом методе окна без полей прекрасно имитируют эффекты Aero Snap в разных направлениях. Это работает, может быть, не так хорошо, но, как я вижу, нет API для эффектов Aero. Может быть, такой подход будет нормальным для тебя.

В Qt есть Aero Peek: http://qt-project.org/doc/qt-5/qtwinextras-overview.html , но это не может решить эту проблему тоже.

Код:

bool left = true;
bool upper = true;

if(upper)
{
QRect rect = QApplication::desktop()->availableGeometry(-1);
this->setGeometry(rect);
}
else if(left)
{
QRect rect = QApplication::desktop()->availableGeometry(-1);
rect.setWidth(rect.width()/2);
this->setGeometry(rect);
}
else
{
QRect rect = QApplication::desktop()->availableGeometry(-1);
int half = rect.width()/2;
rect.setX(half);
rect.setWidth(half);
this->setGeometry(rect);
}

Попробуйте это с безрамным окном! Вы должны выбрать одно направление или позволить пользователю выбрать его.

3