特定のウィンドウ/ウィンドウ ID に対して C または C++ を使用して Aera の最大化効果をプログラムで呼び出す方法はありますか?
例えば:
また
(ソース: thebuzzmedia.com )
ボーダレス Qt ウィンドウを使用していますが、Qt にはウィンドウ ID を取得するための API があります。既知のトリガーを使用せずに、Windows の効果をプログラムでトリガーしたいと考えています。
この効果を実現するために必要なすべての詳細についてはお話ししたくありません。多くのことが行われているだけでなく、特定の場所にウィンドウを配置するロジックを理解しているとおっしゃいました。この回答では、私が考える 2 つの主な課題について説明します。
最大化イベントを受け取って処理する方法は?
エアロスナップ効果の近似値を作成する方法は?
最初の質問に答えるには、ウィンドウが最大化されたときにトリガーされるイベント ハンドラーを分析する必要があります。
void resizeEvent(QResizeEvent* evt); // Invoked first,
void paintEvent(QPaintEvent* event); // then second,
void changeEvent(QEvent* evt); // and at last.
Qt アプリケーションは、最初に が通知され、その後にウィンドウ (またはウィジェット) を描画するためのresizeEvent()
が続き、paintEvent()
すべてが表示された後でのみchangeEvent()
、ウィジェットが最大化されたことを知らせるために呼び出されます (受け取るのが少し遅れるかもしれません)。そのような通知、私は知りません)。
これらすべてのうち、私たちが気にするのは だけですresizeEvent()
。このイベント ハンドラーは、デスクトップ サイズとの比較に使用できる新しいウィンドウ/ウィジェット サイズを通知するため、イベントが実際に最大化要求であったかどうかを知ることができます。最大化リクエストを特定すると、アプリケーションを画面の右、左、または中央に最大化 (および固定) する必要があるかどうかを判断できます。
ここで、エアロ スナップ ウィジェットを作成し、ユーザーへの視覚的な手がかりとして画面に配置します。
2 番目の質問に答えるために、ネイティブ Windows API を呼び出して、ウィンドウでこの効果を実行するよう丁寧に依頼することはできないと思います。他の唯一の論理的な選択肢は、この効果を自分で近似するコードを作成することです。
視覚的な外観は、影のような境界線を持つ透明なウィンドウを描画することで再現できます。以下のソース コードに示されているアプローチでは、 を作成およびカスタマイズして、エアロ スナップウィンドウ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);
}
これは、正しい方向性を示すための簡単なデモです。探している効果の完全な実装ではありません。
必要なものではないかもしれませんが、この効果はウィンドウのサイズを変更して移動するだけで、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()
、さまざまな解像度の画面で適切に動作します。
Web で に似たものを見つけました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 を呼び出す興味深いメソッドが 1 つあります。必要な画面の通常の高さを返します。この方法では、ボーダレス ウィンドウがさまざまな方向で Aero スナップ効果を完全にシミュレートします。動作しますが、あまり良くないかもしれませんが、ご覧のとおり、Aero エフェクト用の API はありません。たぶん、このアプローチはyooにとっては普通でしょう。
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);
}
フレームレスウィンドウで試してみてください!1 つの方向を選択するか、ユーザーに選択させる必要があります。