RichTextBox 的 AnimateWindow API 透明度问题
我正在使用 AnimateWindow
API 来显示或隐藏带有幻灯片动画的 Form
。问题是,如果表单包含 RichTextBox
控件,则它无法正确显示该控件。它是透明的,不显示任何文字。
动画完成后,双击控件中的某处将显示文本行。
我创建了一个完整的示例,任何人都可以使用它来自行编译和测试。除非您已经知道答案,否则没有更好的方法来调试此问题。
主窗体中有 2 个按钮,一个用于显示另一个窗体,另一个用于隐藏同一窗体。我已将 RichTextBox
添加为简单的 TextBox
。正如您将看到的,问题仅发生在 RichTextBox
上。
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApplication1 {
static class Program {
public const int AW_ACTIVATE = 0x00020000;
public const int AW_HIDE = 0x00010000;
public const int AW_HOR_NEGATIVE = 0x00000002;
public const int AW_HOR_POSITIVE = 0x00000001;
public const int AW_SLIDE = 0x00040000;
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AnimateWindow(IntPtr hWnd, int time, int awFlags);
[STAThread]
public static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
public class Form1 : Form {
public Form form;
public Form1() {
InitializeComponent();
form = new Form2();
form.Show();
form.Hide();
}
private void button1_Click(object sender, EventArgs e) {
form.Location = new Point(Location.X, Location.Y + form.Height + 100);
Program.AnimateWindow(form.Handle, 1000, Program.AW_SLIDE | Program.AW_HOR_NEGATIVE | Program.AW_ACTIVATE);
form.Show();
}
private void button2_Click(object sender, EventArgs e) {
Program.AnimateWindow(form.Handle, 1000, Program.AW_HIDE | Program.AW_HOR_POSITIVE);
form.Hide();
}
#region Windows Form Designer generated code
private void InitializeComponent() {
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();
this.button1.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.button1.Location = new System.Drawing.Point(11, 12);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(133, 114);
this.button1.TabIndex = 0;
this.button1.Text = "SHOW";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
this.button2.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.button2.Location = new System.Drawing.Point(150, 12);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(133, 114);
this.button2.TabIndex = 1;
this.button2.Text = "HIDE";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(294, 138);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
}
public class Form2 : Form {
public Form2() {
InitializeComponent();
}
#region Windows Form Designer generated code
private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form2));
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Top;
this.richTextBox1.Location = new System.Drawing.Point(0, 0);
this.richTextBox1.Name = "richTextBox1";
this.richTextBox1.Size = new System.Drawing.Size(240, 50);
this.richTextBox1.TabIndex = 0;
this.richTextBox1.Text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.";
this.textBox1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.textBox1.Location = new System.Drawing.Point(0, 57);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.textBox1.Size = new System.Drawing.Size(240, 50);
this.textBox1.TabIndex = 1;
this.textBox1.Text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.";
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(240, 107);
this.ControlBox = false;
this.Controls.Add(this.textBox1);
this.Controls.Add(this.richTextBox1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Name = "Form2";
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "Form2";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.RichTextBox richTextBox1;
private System.Windows.Forms.TextBox textBox1;
}
}
注意:我正在为此启动悬赏,所以如果您要回答,请回答一个有效的解决方案,而不是让我尝试看看它是否有效。为什么?因为如果人们对你的答案投了赞成票并且没有解决任何问题,它仍然会被标记为已接受,但这没有帮助。感谢您的理解。
I'm using the AnimateWindow
API to show or hide a Form
with a slide animation. The problem is that if the Form contains a RichTextBox
control, it doesn't display this control correctly. It's transparent and doesn't show any text.
After the animation is complete, double clicking somewhere in the control will reveal lines of text.
I've created a full sample that anyone can use to compile and test themselves. There's no better way to debug this, unless you already know the answer.
There's 2 buttons in the main form, one to show another form and the other to hide that same form. I've added both the RichTextBox
as a simple TextBox
. As you'll see, the problem only happens on the RichTextBox
.
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApplication1 {
static class Program {
public const int AW_ACTIVATE = 0x00020000;
public const int AW_HIDE = 0x00010000;
public const int AW_HOR_NEGATIVE = 0x00000002;
public const int AW_HOR_POSITIVE = 0x00000001;
public const int AW_SLIDE = 0x00040000;
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AnimateWindow(IntPtr hWnd, int time, int awFlags);
[STAThread]
public static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
public class Form1 : Form {
public Form form;
public Form1() {
InitializeComponent();
form = new Form2();
form.Show();
form.Hide();
}
private void button1_Click(object sender, EventArgs e) {
form.Location = new Point(Location.X, Location.Y + form.Height + 100);
Program.AnimateWindow(form.Handle, 1000, Program.AW_SLIDE | Program.AW_HOR_NEGATIVE | Program.AW_ACTIVATE);
form.Show();
}
private void button2_Click(object sender, EventArgs e) {
Program.AnimateWindow(form.Handle, 1000, Program.AW_HIDE | Program.AW_HOR_POSITIVE);
form.Hide();
}
#region Windows Form Designer generated code
private void InitializeComponent() {
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();
this.button1.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.button1.Location = new System.Drawing.Point(11, 12);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(133, 114);
this.button1.TabIndex = 0;
this.button1.Text = "SHOW";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
this.button2.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.button2.Location = new System.Drawing.Point(150, 12);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(133, 114);
this.button2.TabIndex = 1;
this.button2.Text = "HIDE";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(294, 138);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
}
public class Form2 : Form {
public Form2() {
InitializeComponent();
}
#region Windows Form Designer generated code
private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form2));
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Top;
this.richTextBox1.Location = new System.Drawing.Point(0, 0);
this.richTextBox1.Name = "richTextBox1";
this.richTextBox1.Size = new System.Drawing.Size(240, 50);
this.richTextBox1.TabIndex = 0;
this.richTextBox1.Text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.";
this.textBox1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.textBox1.Location = new System.Drawing.Point(0, 57);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.textBox1.Size = new System.Drawing.Size(240, 50);
this.textBox1.TabIndex = 1;
this.textBox1.Text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.";
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(240, 107);
this.ControlBox = false;
this.Controls.Add(this.textBox1);
this.Controls.Add(this.richTextBox1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Name = "Form2";
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "Form2";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.RichTextBox richTextBox1;
private System.Windows.Forms.TextBox textBox1;
}
}
NOTE: I'm starting a bounty on this so if you're going to answer, please answer with a solution that works and not something for me to try and see if it works. Why? Because if people upvote your answer and doesn't fix anything , it will still be marked as accepted which it didn't help. Thanks for understanding.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
请查看这段代码...这是我见过的最奇怪的错误...唯一的区别是我必须捕获 RichTextBox 的 VisibleChanged 事件,并设置
Capture
属性,更新它,然后关闭Capture
,我认为应该向控件发送一条消息以强制双击事件,但发现这不是必需的...我还必须覆盖form2
本身的 OnActivated 事件,以便在动画完成后捕获事件并强制刷新......奇怪的错误......代码有效尽管如此 - 一件非常晦涩的事情 - 有趣的是在
VisibleChanged
处理程序中,我原以为单击“隐藏”按钮时调试输出会显示“InVisible”,但事实并非如此。我确实尝试使用WM_PRINT
和WM_PRINTCLIENT
消息,但在富文本框上失败了,只是不要问我为什么在富文本框本身上设置捕获并强制刷新解决了它...这是来自 的引用MSDN 对此:我不知道是否值得向 Microsoft 指出这一点并说“AnimateWindow 或带有 .NET 的 RichTextBox 控件中存在错误”,无论哪种方式,都很难确定,因为动画完成后,文本框显示正常,但富文本框显示不正常,但在捕获打开时显式使用
Capture
和Update
强制刷新。它在错误本身上双向摆动 - 可能在两个地方......无论如何都很不寻常和奇怪......希望代码对你有用。Please see this code... this is the most bizarre bug I've ever seen... the only difference is that I had to trap the VisibleChanged Event for the RichTextBox, and to set the
Capture
property, update it, then switch off theCapture
, my thinking there was to send a message to the control to force a double-click event but discovered that is not required... I also had to override the OnActivated event for theform2
itself in order to get the event trapped AFTER the animation is done and to force a refresh...strange bizarre bug....The code works nonetheless - a very obscure thing - the funny thing is within the
VisibleChanged
handler, I was expecting the debug output to say "InVisible" when clicking on the 'Hide' button but it did not. I did try usingWM_PRINT
andWM_PRINTCLIENT
message which failed with the rich-text-box, just don't ask me why setting the capture on the rich-text-box itself and forcing a refresh solved it... Here's the quote from MSDN on this:I do not know if it's worth the trouble in pointing this out to Microsoft and say "There's a bug either in the AnimateWindow or in the RichTextBox Control with .NET", either way, it is difficult to ascertain, since after the animation is done, the text-box appears ok, but not the rich-text-box, yet explicitly using the
Capture
and theUpdate
when the capture is on, forced a refresh... it swings both ways on the bug itself - could be in both spots... Very unusual and bizarre anyway.. hope the code is of use to you.RichTextBox 不处理 WM_PRINT 消息,我相信 AnimateWindow 在幕后使用的是什么,所以我看不到任何使用富文本框中可见的文本执行动画的方法(如果您希望富文本框显示文本)动画期间)。
动画完成后,您可以调用 richTextBox1.Refresh (通过 Form2 类中的辅助方法在您的 button1_Click 中)来重新绘制框 - 带有文本的控件将正常显示,无需任何双击。
The RichTextBox does not process WM_PRINT messages, which is I believe what AnimateWindow uses behind the scenes, so I don't see any way of doing the animation with the text visible in your rich text box (in case you want richtext box to display text during the animation).
When the animation is complete you can call richTextBox1.Refresh (in your button1_Click via a helper method in the Form2 class) for the box to repaint - the control with the text will be shown alright without any double-clicking.
WPF 不包含您需要的幻灯片动画吗?
像 AnimateWindow 这样的 API...在 Microsoft 中并没有得到太多关注 - 通常支持“更好”的 .NET / WPF 方法。使用本机/非托管 API 来设置窗口动画很快会让您陷入痛苦的世界:- Microsoft 不支持本机控件和窗口中的闪烁控制动画或 alpha 效果。
如果目标窗口具有航空玻璃,则本机 AnimateWindow 往往会翻倒。任何非客户端元素。任何孩子都可以控制。任何透明度(窗口区域、带有 Alpha 或遮罩的分层窗口)。
它真的根本没有那么好用。
解决这个问题的唯一方法是执行 AnimateWindow 所做的事情。 AnimateWindow 与其说是 API 调用,不如说是用户可以“轻松”实现的功能的便捷包装。
AnimateWindow 所做的一切,就是在计时器上重新定位动画窗口。根据动画,它将在动画持续时间内使用剪辑区域,或添加 WS_EX_LAYERED 样式(以进行 alpha 混合)。这就是为什么当给定窗口已经使用这些效果时 AnimateWindow 会如此失败。
自己执行动画时,您可以尝试调整参数以更符合丰富的编辑绘画要求。
Does WPF not contain the slide animations you need?
APIs like AnimateWindow are ... not given a lot of attention at Microsoft - usually in favor of a 'better' .NET / WPF method. Using native / not managed APIs to animate windows quickly lands you in a world of hurt :- Microsoft do not support flicker control animations - or alpha effects - in native controls and windows.
The native AnimateWindow tends to fall over if the target window has aero glass. any non-client elements at all. Any child controls. any transparency (window regions, layered windows with alpha or masking).
It really just doesn't work that well at all.
The only way to work around it would be to do what AnimateWindow does. AnimateWindow is not so much an API call, but a convenience wrapper around functionality that can "easilly" be implemented by the user.
All that AnimateWindow does it, well, reposition the animated window on a timer. Depending on the animation it will use clip regions, or add the WS_EX_LAYERED style (to do the alpha blends) for the duration of the animation. This is why AnimateWindow fails so spectacularly when given windows already using those effects.
Performing the animation yourself, you can try to tweak the parameters to do it in a way more compatible with the rich edits painting requirements.