簡體   English   中英

以編程方式調用Snap / Aero最大化

[英]Programmatically invoke Snap/Aero maximize

有沒有辦法以編程方式使用C或C ++為特定的窗口/窗口ID調用Aera最大化效果?

例如:

在此輸入圖像描述

要么

在此輸入鏈接說明http://www.thebuzzmedia.com/wp-content/uploads/2009/05/windows-7-aero-snap-to-edge-effect.png

我使用的是無邊框Qt窗口,Qt有一個用於獲取窗口ID的API。 我想以編程方式觸發Windows效果而不使用已知的觸發器。

我不想談論實現這種效果所涉及的每一個細節,不僅有很多事情發生,而且你還提到你理解將窗口放在特定位置的邏輯。 在這個答案中,我將解決我認為的兩個主要挑戰:

  • 如何接收和處理最大化事件?

  • 如何創建近似的航空按扣效果?

為了回答第一個問題 ,我們必須分析窗口最大化時觸發的事件處理程序

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小部件並將其作為用戶視覺線索放置在屏幕上的時間。

要回答第二個問題 ,我認為無法調用本機Windows API並禮貌地請求它在您的窗口上執行此效果。 唯一合乎邏輯的選擇是編寫一個自己近似於這種效果的代碼。

可以通過繪制帶陰影邊框的透明窗口來復制視覺外觀。 在下面的源代碼中演示的方法,創建並自定義QWidget ,使其行為和看起來像一個航空快照窗口:

在此輸入圖像描述

我知道,這不是世界上最美麗的事物。 此演示為用戶創建一個常規窗口進行交互,一旦最大化,它就會將自己置於屏幕左側。 對於正確尺寸的屏幕,它會顯示類似於航空快照窗口的內容(如上所示)。

aero snap小部件背后的想法非常簡單 :具有透明背景和自定義繪制過程的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);
}

這只是一個快速演示,可以指出您正確的方向。 它絕不是您正在尋找的效果的完整實現。

也許它不是你需要的,但這個效果只是調整大小和移動窗口然后嘗試使用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()調節左右兩側,但PostMessagewinapi )在每個屏幕上正確設置窗口的高度(窗口不會低於taskbar ,如在您的示例中)

編輯

我改變了一點代碼,現在它變得更好了。 是的,它再次調整大小,但現在它沒有winapi代碼( PostMessage等),所以Photoshop沒有捕獲它,Qt中有一個有趣的方法叫做availableGeometry。 它返回我們需要的正常屏幕高度,這種方法無邊框窗口完美地模擬不同方向的Aero Snap效果。 這是有效的,也許不是那么好,但正如我所看到的,Aero效果沒有API。 也許這種方法對於你來說是正常的。

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

嘗試使用無框窗口! 您應該選擇一個方向或讓用戶選擇它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM