Проблема прозрачности API AnimateWindow с RichTextBox - PullRequest
2 голосов
/ 18 августа 2010

Я использую 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;
    }
}

ПРИМЕЧАНИЕ: Я начинаю вознаграждение за это, поэтому, если вы собираетесь ответить, пожалуйста, ответьте с решением, которое работает, а не что-то для меня, чтобы попробовать и посмотреть, работает ли оно . Зачем? Потому что, если люди проголосуют за ваш ответ и ничего не исправят, он все равно будет помечен как принятый, что не помогло. Спасибо за понимание.

Ответы [ 3 ]

0 голосов
/ 27 августа 2010

Пожалуйста, посмотрите этот код ... это самая странная ошибка, которую я когда-либо видел ... единственное отличие состоит в том, что мне пришлось перехватить событие VisibleChanged для RichTextBox и установить свойство Capture, обновить затем отключите Capture, я подумал, что нужно отправить сообщение элементу управления, чтобы вызвать событие двойного щелчка, но обнаружил, что это не требуется ... Мне также пришлось переопределить событие OnActivation для form2 Сам для того, чтобы поймать событие в ловушку ПОСЛЕ анимация завершена и вызвать обновление ... странная странная ошибка ....

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Text;

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();
            this.richTextBox1.VisibleChanged += new EventHandler(richTextBox1_VisibleChanged);
        }

        void richTextBox1_VisibleChanged(object sender, EventArgs e)
        {
            if (this.richTextBox1.Visible)
            {
                System.Diagnostics.Debug.WriteLine("Visible!");
                this.richTextBox1.Capture = true;
                this.richTextBox1.Update();
                this.richTextBox1.Capture = false;
                this.richTextBox1.Refresh();
            }
            else System.Diagnostics.Debug.WriteLine("InVisible!");
        }

        #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

        protected override void OnActivated(EventArgs e)
        {
            base.OnActivated(e);
            System.Diagnostics.Debug.WriteLine("OnActivated");
            this.Refresh();
        }

        private System.Windows.Forms.RichTextBox richTextBox1;
        private System.Windows.Forms.TextBox textBox1;
    }
}

Код работает, тем не менее - очень непонятная вещь - забавная вещь в обработчике VisibleChanged, я ожидал, что выходные данные отладки скажут «InVisible» при нажатии на кнопку «Скрыть», но это не так. Я попытался использовать сообщения WM_PRINT и WM_PRINTCLIENT, которые не удалось выполнить с помощью rich-text-box, просто не спрашивайте меня, почему установка захвата на самом rich-text-box и принудительное обновление решили эту проблему ... Вот цитата из MSDN на это:

Оконные процедуры для окна и его дочерних окон должны обрабатывать любые сообщения WM_PRINT или WM_PRINTCLIENT. Диалоговые окна, элементы управления и общие элементы управления уже обрабатывают WM_PRINTCLIENT. Оконная процедура по умолчанию уже обрабатывает WM_PRINT. Если дочернее окно отображается частично обрезанным, то при анимации оно будет иметь отверстия, в которых оно будет обрезано.

Я не знаю, стоит ли пытаться указать на это Microsoft и сказать: «В AnimateWindow или в элементе управления RichTextBox с .NET есть ошибка, так или иначе, это трудно установить, так как после анимация завершена, текстовое поле отображается нормально, но не расширенное текстовое поле, но явно при использовании Capture и Update, когда захват включен, принудительное обновление ... оно качается в обоих направлениях Сама ошибка - может быть в обоих местах ... Очень необычно и причудливо в любом случае .. надеюсь, код вам пригодится.

0 голосов
/ 28 августа 2010

RichTextBox не обрабатывает сообщения WM_PRINT, то есть, я полагаю, что AnimateWindow использует за кулисами, поэтому я не вижу никакого способа сделать анимацию с текстом, видимым в вашем поле расширенного текста (на случай, если вам нужно поле расширенного текста). для отображения текста во время анимации).

Когда анимация будет завершена, вы можете вызвать richTextBox1.Refresh (в вашем button1_Click с помощью вспомогательного метода в классе Form2), чтобы поле перерисовывалось - элемент управления с текстом будет отображаться без двойного щелчка.

0 голосов
/ 18 августа 2010

Разве в WPF нет нужной вам анимации слайдов?

API-интерфейсам, таким как AnimateWindow ... не уделяется много внимания в Microsoft - обычно в пользу «лучшего» метода .NET / WPF. Использование собственных / неуправляемых API-интерфейсов для анимации окон быстро переносит вас в мир боли: - Microsoft не поддерживает анимацию мерцания и альфа-эффекты в собственных элементах управления и окнах.

Собственное окно AnimateWindow имеет тенденцию падать, если в целевом окне есть аэростекло. любые не клиентские элементы вообще. Любой ребенок контролирует. любая прозрачность (области окна, многослойные окна с альфа-каналом или маскированием).

Это на самом деле просто не очень хорошо работает.


Единственный способ обойти это - делать то, что делает AnimateWindow. AnimateWindow - это не столько вызов API, сколько удобная оболочка вокруг функциональности, которую пользователь может «легко» реализовать.

Все, что делает AnimateWindow, ну и перемещает анимированное окно по таймеру. В зависимости от анимации он будет использовать области обрезки или добавит стиль WS_EX_LAYERED (для создания альфа-смесей) на время анимации. Вот почему AnimateWindow так неудачно завершает работу, если для заданных окон уже используются эти эффекты.

Выполняя анимацию самостоятельно, вы можете попытаться настроить параметры, чтобы сделать ее более совместимой с требованиями рисования rich edit.

...