- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
描述
我有一个 Delphi XE2 应用程序,其中一种形式跨越两个显示器。当我锁定 Windows 时,等到屏幕保护程序被激活,然后解锁窗口,我的所有应用程序的窗体都将调整大小/重新定位以适应每个显示器(这显然是默认的 Windows 行为并适用于大多数应用程序)。
意图
每当发生这种锁定情况时,我要么想恢复我的表单位置,要么阻止我的表单事先调整大小。
重现步骤
这些步骤适用于 Windows 7 x64。
我正在设置一个在 1 分钟后激活的黑屏保护程序。我打开我的应用程序和适当的拉伸(stretch)形式。我锁定
我的帐户并等待屏幕保护程序弹出。登录后,我可以看到已调整大小的表单。
在其他机器上锁定足以重现该行为。在某些机器上,激活的屏幕保护程序就足够了。
附加信息
到目前为止我所做的和观察到的:
Spy++
我发现我的应用程序收到了 WM_SETTINGCHANGE
消息,其中 WParam
= SPI_SETWORKAREA
。此时我的表单已经有了新的大小。WM_SETTINGCHANGE
时,表单大小已更改并缩小到一个显示器。SetWindowPos
。wsNormal
。我以编程方式将窗体拉伸(stretch)到两个显示器上方,但不触及它的窗口状态。WM_WTSSession_Change
解锁消息上恢复旧的(内部保存的)位置/大小,我尝试调用SetWindowPos(Handle, HWND_NOTOPMOST, FFormSizePos.Left, FFormSizePos.Top, FFormSizePos.Width, FFormSizePos.Height, SWP_NOACTIVATE or SWP_NOMOVE);
Self.Left := FFormSizePos.Left;
谁能帮忙解决我的意图?
最佳答案
我找到了解决方案并发布了演示代码 (XE2) 作为此问题的 Delphi 解决方案。
它是 answer here 的组合和解决方案 1 来自 delphiDabbler .
基本上我正在注册 Windows session 状态更改事件 (WM_WTSSESSION_CHANGE
)。在提供的示例(基于裸 VCL 表单应用程序)中,我使用 WM_EXITSIZEPOS
消息来保存当前表单 sizepos。
Windows 在触发位置更改消息时表现出不同的行为。这就是为什么我不得不修改我的初稿并且现在使用两个变量。我在 session 锁定时防止位置更改,并在 session 解锁后防止第一次位置更改。使用 WM_WINDOWPOSCHANGING
消息拦截位置更改。
但为了在表单最大化时不恢复正常位置,我使用了 FRestoreNormalRect 字段。
unit Unit1;
interface
uses
Winapi.Windows,
Winapi.Messages,
Vcl.Forms;
type
TForm1 = class(TForm)
private
FSessionIsLocked: Boolean;
FSessionWasUnlocked: Boolean;
FRestoreNormalRect: Boolean;
FLeft: Integer;
FTop: Integer;
FWidth: Integer;
FHeight: Integer;
procedure WMWTSSessionChange(var Msg: TMessage); message WM_WTSSESSION_CHANGE;
protected
procedure CreateWnd; override;
procedure DestroyWnd; override;
procedure WMExitSizeMove(var Msg: TMessage); message WM_EXITSIZEMOVE;
procedure WMPosChanging(var Msg: TWmWindowPosChanging); message WM_WINDOWPOSCHANGING;
procedure WMSize(var Msg: TWMSize); message WM_SIZE;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//--------------------------------------------------------------------------------------------------
procedure TForm1.CreateWnd;
begin
inherited;
WTSRegisterSessionNotification(WindowHandle, NOTIFY_FOR_THIS_SESSION);
end;
//--------------------------------------------------------------------------------------------------
procedure TForm1.DestroyWnd;
begin
WTSUnRegisterSessionNotification(WindowHandle);
inherited;
end;
//--------------------------------------------------------------------------------------------------
procedure TForm1.WMExitSizeMove(var Msg: TMessage);
var
WP: TWindowPlacement;
NormalRect: TRect;
begin
WP.Length := SizeOf(TWindowPlacement);
GetWindowPlacement(Self.Handle, @WP);
NormalRect := WP.rcNormalPosition;
FLeft := NormalRect.Left;
FTop := NormalRect.Top;
FWidth := NormalRect.Right - NormalRect.Left;
FHeight := NormalRect.Bottom - NormalRect.Top;
end;
//--------------------------------------------------------------------------------------------------
procedure TForm1.WMPosChanging(var Msg: TWmWindowPosChanging);
begin
{ Sizepos changes might occur due to locks or unlocks. We need do prohibit both.
While the session is locked we ignore all position changes.
When the session has been unlocked we will ignore the next PosChanging message. }
if FSessionIsLocked or FSessionWasUnlocked then
begin
{ overwrite with the old settings }
if FRestoreNormalRect then
begin
Msg.WindowPos.x := FLeft;
Msg.WindowPos.y := FTop;
Msg.WindowPos.cx := FWidth;
Msg.WindowPos.cy := FHeight;
Msg.Result := 0;
end;
{ reset the variable, otherwise a manual resize would not be possible }
if FSessionWasUnlocked then
FSessionWasUnlocked := False;
end;
end;
//--------------------------------------------------------------------------------------------------
procedure TiQForm.WMSize(var Msg: TWMSize);
begin
inherited;
{ We need to restore our normal rect only if the form is not maximized. Because
if it is maximized it only positioned on one monitor and will not be moved
by windows. If we do not repsect this case we would be restoring the normal
rect unintentionally in WMPosChanging for every maximized form. }
FRestoreNormalRect := not (Msg.SizeType = SIZE_MAXIMIZED);
end;
//--------------------------------------------------------------------------------------------------
procedure TForm1.WMWTSSessionChange(var Msg: TMessage);
begin
case Message.WParam of
WTS_CONSOLE_DISCONNECT, WTS_REMOTE_DISCONNECT, WTS_SESSION_LOCK, WTS_SESSION_LOGOFF:
begin
FSessionIsLocked := True;
end;
WTS_CONSOLE_CONNECT, WTS_REMOTE_CONNECT, WTS_SESSION_UNLOCK, WTS_SESSION_LOGON:
begin
FSessionIsLocked := False;
FSessionWasUnlocked := True;
end;
end;
inherited;
end;
//--------------------------------------------------------------------------------------------------
end.
关于windows - Windows session 解锁后如何防止窗体位置大小发生变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22249149/
对于一个科学实验,我写了一个turtle.py ,它会打开一个 800x480 的窗口并绘制一个缓慢增长的黑点。 turtle.py以 C:\Users\kaza>python C:\Users\ka
我开发了一个 swing 应用程序,但每次运行应用程序时都会打开一个新窗口。我希望如果一个窗口已经打开,则其他窗口不允许打开。 最佳答案 Here是一个 Java 单一应用实例的例子: A singl
有没有办法检测主进程中 Electron 的结构? process.platform 似乎也在 x64 机器上返回 win32,我没有在文档中找到任何获取架构的选项。 最佳答案 你试过 process
public short[] HanningWindow(short[] signal_in ,int pos ,int size) { for (int i= pos; i < pos+si
我有一个具有这些属性的 Electron 窗口: mainWindow = new BrowserWindow({ width: 800, height: 600, title: "Aqu
我有一个 Ubuntu 工作站,我正在尝试引导一个 Windows 节点。 Windows 节点在端口 2222 上打开了 ssh。我一直在关注 http://docs.opscode.com/plu
我是一名优秀的程序员,十分优秀!