c++ - 以编程方式调用 Snap/Aero 最大化

标签 c++ qt winapi aero aero-snap

有没有一种方法可以使用 C 或 C++ 为特定窗口/窗口 ID 以编程方式调用 Aera 最大化效果?

例如:

enter image description here

enter link description here
(来源:thebuzzmedia.com)

我正在使用一个无边框的 Qt 窗口,Qt 有一个获取窗口 ID 的 API。我想在没有已知触发器的情况下以编程方式触发窗口效果。

最佳答案

我不想谈论实现此效果所涉及的每一个细节,不仅要进行很多操作,而且您还提到您了解将窗口放置在特定位置的逻辑。在这个回答中,我将解决我认为的 2 个主要挑战:

  • 如何接收和处理maximize事件?

  • 如何创建aero snap 效果的近似值?

为了回答第一个问题,我们必须分析哪些event handlers当窗口最大化时触发:

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

Qt 应用程序首先收到 resizeEvent() 的通知,然后是 paintEvent() 以绘制窗口(或小部件),并且仅在所有内容之后已显示,changeEvent() 被调用,让您知道小部件已最大化(也许收到此类通知有点晚,我不知道)。

在所有这些中,我们唯一关心的是 resizeEvent()。此事件处理程序通知可用于与桌面大小进行比较的新窗口/小部件大小,从而让我们知道该事件是否实际上是最大化请求。一旦我们确定了最大化请求,我们就可以确定应用程序应该最大化(并锚定)到还是中心的屏幕。

现在是创建aero snap 小部件 并将其放置在屏幕上作为用户视觉线索的时候了。

要回答第二个问题,我认为调用 native Windows API 并礼貌地要求它在您的窗口上执行此效果是不可能的。唯一的其他合乎逻辑的选择是自己编写一个近似于这种效果的代码。

可以通过绘制带有阴影边框的透明窗口来复制视觉外观。下面源代码中演示的方法创建并自定义了一个 QWidget,使其行为和外观都像一个 aero snap 窗口:

enter image description here

我知道,这不是世界上最美丽的事物。该演示创建了一个供用户交互的常规窗口,一旦最大化,它就会将自己置于屏幕左侧。在屏幕大小合适的情况下,它会显示类似于 aero snap 窗口的内容(如上所示)。

aero snap widget 背后的想法非常简单:一个具有透明背景和自定义绘画程序的 QWidget。换句话说,它是一个透明窗口,它绘制了一个带阴影的圆角矩形,仅此而已。

为了让它更逼真一点,您应该添加一些动画来一点一点地调整小部件的大小。 for 循环可能可以解决问题,但如果您需要一些花哨的东西,您最终会使用计时器。如果你拿 look here ,您可以看到使用 Qt 执行动画的最快和最脏的方法,以及处理动画的更好方法。但是,对于像这样的简单任务,请坚持使用 frame-based animation .

ma​​in.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);
}

这只是一个快速演示,可为您指明正确的方向。它绝不是您正在寻找的效果的完整实现。

关于c++ - 以编程方式调用 Snap/Aero 最大化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25833996/

相关文章:

c++ - 是否有相当于这个 "safe_read"调用的 boost

c++ - 无法使用 FFMPEG API 将 H264 配置文件从 Main 更改为 High

c++:在不同链接库中定义的相同函数的运行时冲突

windows - 触摸屏隐藏光标

c++ - 从 'std::istream&'类型的表达式中获取 'int'类型的引用的无效初始化

c++ - 在 C++ 中的编译时检索输出目标名称作为字符串

c++ - 简单的智能感知解决方案

c++ - Qt - 关于头文件的一些问题

c++ - 为什么这段代码可以编译?

multithreading - 等待线程中的特定时间,使用WaitForSingleObject?