编程调用Snap / Aero最大化 [英] Programatically invoke Snap/Aero maximize

查看:367
本文介绍了编程调用Snap / Aero最大化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



例如:









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

解决方案

我不想谈论每一个细节在实现这个效果,不仅有很多,但你也提到你理解的逻辑,把窗户放在他们的特定位置。在这个答案中,我将说明我认为的两个主要挑战:




  • 如何接收和处理 最大化


  • 如何创建 >效果?

  • 必须分析哪个,您可以看到最快的&最脏的方法来执行动画与Qt在行动,以及更好的方式来处理动画。但是,对于像这样的简单任务,请遵循 基于帧的动画



    main.cpp

      #includewindow.h
    #include< QApplication>

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

    return app.exec();
    }

    window.h

      #pragma once 
    #includesnapwindow.h
    #include< QMainWindow>
    #include< QEvent>

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

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

    private:
    SnapWindow * _sw;
    };

    window.cpp

      #includewindow.h
    #includesnapwindow.h

    #include< QDebug>
    #include< QWindowStateChangeEvent>
    #include< QApplication>
    #include< QDesktopWidget>

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

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

    无效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!;
    }
    }
    }

    //在window_maximized事件之前触发resizeEvent
    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();

    //显然,一个窗口在我的系统中可以拥有的最大大小(1920x1080)
    //实际上是1920x990。我怀疑这是因为任务栏有90px的高度:
    desktop_sz.setHeight(desktop_sz.height() - 90);

    //如果这不是最大化窗口的请求,不要做任何疯狂。
    if(desktop_sz.width()!= evt-> size()。width()||
    desktop_sz.height()!= evt-> size b $ b return;

    //好了,现在我们知道这是一个最大化请求:
    qDebug()<< resizeEvent:向左最大化此窗口;

    //所以我们更新窗口几何(即大小和位置)
    //到我们认为合适的:左边的一半宽度
    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和高度-45是由于90px问题

    / *绘制aero快照小部件* /

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

    //在这个方法结束后,paintEvent()会被自动调用,
    //并且会用适当的几何来绘制这个窗口。
    }

    snapwindow.h

      #pragma once 
    #include< QWidget>

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

    void paintEvent(QPaintEvent * event);
    };

    snapwindow.cpp

      #includesnapwindow.h
    #include< QPainter>
    #include< QGraphicsDropShadowEffect>

    SnapWindow :: SnapWindow(QWidget * parent)
    :QWidget(parent)
    {
    //将此窗口小部件设置为顶级(即由用户拥有)
    setParent(0);

    / *看看:创建透明窗口的魔力* /

    setWindowFlags(Qt :: Widget | Qt :: FramelessWindowHint);
    setStyleSheet(background:transparent;);
    setAttribute(Qt :: WA_NoSystemBackground,true); //通过删除不必要的后台初始化加快绘制
    setAttribute(Qt :: WA_TranslucentBackground);
    // setAutoFillBackground(true);

    / *使用Qt技巧绘制阴影的东西* /

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

    / *绘制阴影的延迟方式* /

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

    //偏移6和9像素,所以阴影正确显示
    painter.drawRoundedRect(QRect(6,6,(width() - 1)-9, 1)-9),18,18);
    }

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


    Is there a way to programmatically invoke the Aera maximize effect using C or C++ for a specific window/window ID?

    For example:

    or

    I am using a border-less Qt window and Qt has an API for getting the window ID. I want to programmatically trigger the windows effects without the known triggers.

    解决方案

    I don't want to talk about every single detail involved in achieving this effect, not only there's a lot that goes on but you also mentioned you understand the logic to place the windows at their specific locations. In this answer I'll address what I believe are the 2 main challenges:

    • How to receive and handle a maximize event?

    • How to create an approximation of the aero snap effect?

    In order to answer the first question, we must analyze which event handlers are triggered when the window is maximized:

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

    A Qt application is first notified of a resizeEvent(), which is followed by a paintEvent() to draw the window (or widget), and only after everything has been displayed, changeEvent() is invoked to let you know the widget was maximized (maybe it's a little bit late to receive such notification, I don't know).

    Of all these, the only one we care about is resizeEvent(). This event handler informs the new window/widget size that can be used for comparison with the desktop size, thus allowing us to know if the event was actually a maximize request. Once we identify a maximize request, we can figure out whether the application should be maximized (and anchored) to right, left or to the center of the screen.

    This would be the time to create the aero snap widget and place it on the screen as a visual clue to the user.

    To answer the second question, I don't think is possible to call the native Windows API and ask it politely to perform this effect on your window. The only other logical choice is to write a code that approximates this effect ourselves.

    The visual appearance can be replicated by drawing a transparent window with a shadow-ish border. The approach demonstrated in the source code below, creates and customizes a QWidget to make it behave and look like a aero snap window:

    It's not the most beautiful thing in the world, I know. This demo creates a regular window for the user to interact with, and once it's maximized, it places itself to the left of the screen. To the right size of the screen it displays something that resembles an aero snap window (shown above).

    The idea behind the aero snap widget is very simple: a QWidget with transparent background and a custom painting procedure. In other words, it's a transparent window which draws a rounded rectangle with a shadow and that's it.

    To make it a bit more realistic, you should add some animation to resize the widget little by little. A for loop might do the trick, but if you need something fancy you'll end up using timers. If you take a look here, you can see the quickest & dirtiest method to perform animation with Qt in action, and better ways to deal with animation. However, for simple tasks like this, stick with frame-based animation.

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

    This is just a quick demo to point you to the right direction. It is by no means a complete implementation of the effect you are looking for.

    这篇关于编程调用Snap / Aero最大化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆