【问题标题】:Smooth transition between two Forms in VCLVCL中两个Form之间的平滑过渡
【发布时间】:2020-03-18 12:55:51
【问题描述】:

我已经玩了几个小时了,但我无法让它工作。我有一个由两个表格组成的应用程序,我想从一个表格切换到另一个表格。我希望这个开关“平滑”(即混合效果)。

我想出了这个部分可行的解决方案:在 ShowForm() 方法中使用 AnimateWindow 函数。当我从 Form1 切换到 Form2 时,这工作正常。但是切换回 Form1 不起作用。 Form1 被绘制在 Form2 的“后面”,当 Form2 隐藏时,过渡已经完成。

下面是Form1的非常简单的代码:

#include <vcl.h>
#pragma hdrstop

#include "main_form.h"
#include "child_form.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    Form2 -> Show();
    Form1 -> Hide();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
    const int speed = 1000;
    AnimateWindow(Handle, speed, AW_BLEND);
}

这里是Form2的代码:

#include <vcl.h>
#pragma hdrstop

#include "child_form.h"
#include "main_form.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
    Form1 -> Show();
    Form2 -> Hide();

}
//---------------------------------------------------------------------------
void __fastcall TForm2::FormShow(TObject *Sender)
{
    const int speed = 1000;
    AnimateWindow(Handle, speed, AW_BLEND);
}

我试图在 Form2 的代码中反转 Form1-&gt;Show()Form2-&gt;Hide()statements,以在绘制 Form1 之前强制隐藏 Form2,但它也不起作用:Form2 被隐藏,然后在动画期间什么都不显示,并且然后突然显示Form1。

有什么想法吗?

谢谢。

【问题讨论】:

  • 在我的版本(XE7)的帮助下,据说不要直接使用TAnimateWindowProc()。但无论如何,表单都有一个属性AlphaBlend,它启用/禁用表单的字母混合,以及一个随附的AlphaBlendValue。在循环中增加一个表单值 (0..255),同时减少另一个表单值 (255..0) 会给您想要的效果。两种形式都必须有Visible = True
  • @TomBrunberg 感谢您的回复。我实际上在发布此解决方案之前尝试了此解决方案,但它也不起作用。实际上它工作一次。第一次创建每个表单时都可以,然后直接显示表单,没有任何混合。明天我将尝试使用此解决方案的示例代码编辑初始问题。但是,不能控制哪个表格在另一个表格前面确实令人沮丧。
  • 在我的测试中,我在循环中更改了AlphaBlendValue 两种形式,您描述的问题并不那么明显。但它的效果是,由于这两种形式在过渡过程中都是部分透明的,所以后面的东西都会简单地显示出来。我知道你想避免这种情况。您在问题中提出的问题是由于 其中一种形式是主要形式。如果您可以重新排列以使您想要平滑交换的表单是“非主表单”,那么您可以在循环之前将任何表单都放在前面。
  • 确实主要问题是其中一种形式是主要形式。我尝试创建一个空白的第三种形式作为主要形式,黑色背景,部分解决了这个问题。由于目前缺乏更好的解决方案,我会将其发布为答案。您也可以使用 AlphaBlendValue 作为问题的答案来发布您的代码吗?所以我可以检查一下我的区别吗?

标签: c++ c++builder vcl


【解决方案1】:

根据您的要求,这是我对这个主题的看法,但是,由于我对 C++Builder 不满意,在 Delphi 的 pascal 中。

您所描述的问题(行为差异取决于是否将Form1Form2 置于前面)是由于Form1 是主要形式。如果两个表单都不是主表单,则问题不存在。

如果一个表单是主表单,如果您使用AlphaBlendValue 同时更改两个表单的可见性,则问题不太明显,即提高要显示的表单的值并减小另一个表单的值.由于这两种形式都是部分可见的,因此它们的 z 顺序并不像您只更改其中一种形式那样明显。

从一个包含两个表单(我的代码中的 TForm25 和 TForm26)的项目开始。

TForm25
  property AlphaBlend = True
  property AlphaBlendValue = 255
  property Visible = True

TForm26
  property AlphaBlend = True
  property AlphaBlendValue = 0
  property Visible = True

在两个表单都可以访问的地方添加以下代码。

procedure FadeOutIn(FOut, FIn: TForm);
var
  i: integer;
begin
  FIn.BringToFront;
  for i := 1 to 255 do
  begin
    FOut.AlphaBlendValue := 255-i;
    FIn.AlphaBlendValue := i;
    sleep(1); // use 20 for a really slow transition, just to demonstrate
              // or remove if not needed
  end;
end;

在我的测试中,这两种形式都是自动创建的,Visible = True 是自动创建的,但 Form26 不可见,因为它的 AlphaBlendValue = 0。每个表单都有一个按钮来调用FadeOutIn() 以淡出(隐藏)它自己并淡入(显示)另一个表单。

procedure TForm25.Button1Click(Sender: TObject);
begin
  FadeOutIn(Form25, Form26);
end;

procedure TForm26.Button1Click(Sender: TObject);
begin
  FadeOutIn(Form26, Form25);
end;

警告: - 由于两种形式同时是半透明的,所以在过渡过程中,任何隐藏的东西也会显示出来。

【讨论】:

  • 这可以正常工作,但前提是其中一个表单不是主表单。如果其中一种形式是主要形式,我仍然没有得到一个奇怪的效果。我可以在表单之间来回切换一次,然后再次单击 Form1 会短暂显示 Form2(不混合)并直接恢复到 Form1 ...通过添加一个额外的空白表单作为主要表单,它甚至可以完美运行超过 2 个窗口。
【解决方案2】:

按照@TomBrunberg 的建议,这是一个可能的解决方案。这里的主要问题是其中一个 Form 是 MainForm ,它始终位于另一个之后。为了避免这种情况,可以创建第三个空白表格并将其声明为主要表格。此表单Visibleproperty 设置为False。第三种形式的代码如下:


#include <vcl.h>
#pragma hdrstop

#include "background.h"
#include "main_form.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm3 *Form3;
//---------------------------------------------------------------------------
__fastcall TForm3::TForm3(TComponent* Owner)
    : TForm(Owner)
{

}
//---------------------------------------------------------------------------

void __fastcall TForm3::FormShow(TObject *Sender)
{
     Form1->Show();
}
//---------------------------------------------------------------------------

另外两个Form中的代码被修改,使得Hide()方法在Show()之前被调用,如下所示。 表格1:

#include <vcl.h>
#pragma hdrstop

#include "main_form.h"
#include "child_form.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    Form1 -> Visible = false;
    Form2 -> Visible = true;
}

void __fastcall TForm1::FormShow(TObject *Sender)
{
    int const sleep = 500;
    AnimateWindow(Handle, sleep, AW_BLEND);
}

和表格 2

#include <vcl.h>
#pragma hdrstop

#include "child_form.h"
#include "main_form.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
    Form2 -> Visible = false;
    Form1 -> Visible = true;
}
//---------------------------------------------------------------------------

void __fastcall TForm2::FormShow(TObject *Sender)
{
    int const sleep = 500;
    AnimateWindow(Handle, sleep, AW_BLEND);
}

这只是部分工作:在第一次启动时,显示 Form1,没有过渡效果,但不是很重要。但是当第一次调用Form2时,转场效果也不起作用,并且在转场效果期间可以看到空白的Form3。之后,它就可以工作了,两个表单都可以显示过渡效果。

【讨论】:

  • 我不明白为什么Form3 会突然变得可见。你是从Form1 打电话给Form2(正如我所期望的那样)还是......?
  • 是的,我愿意。我编辑了答案以添加表格 1 和 2 的代码。
猜你喜欢
  • 2011-10-11
  • 2014-03-17
  • 1970-01-01
  • 1970-01-01
  • 2011-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多