كيف يمكنني برمجة تأثير "فلاش" عند تحديث مربعات النص في نموذج Windows مع C#؟

StackOverflow https://stackoverflow.com/questions/4147169

سؤال

ما لدي هو نموذج Windows ، في C#، مع 7 مربعات نصية. يقوم كل مربع نص بتحديث 2 أو 3 آخرين عند تغيير قيمته وقبوله. ما أريد القيام به هو أخذ مربعات النص هذه بطريقة ما التي تحتاج إلى تحديثها وجعلها "فلاش" بلون خلفي للضوء أو شيء من هذا القبيل. والغرض من ذلك هو إظهار المستخدم ما يتم تحديثه بقليل من الذوق.

لست متأكدًا مما إذا كانت هناك طريقة سهلة للقيام بذلك وهذا هو السبب في أنني أسأل هنا. يمكنني استخدام جهاز توقيت ، حلقة من الوقت ، ولون خلفي مع قناة ألفا متناقصة على لون مربع النص ، أعتقد ، لكنني أريد أن أرى ما إذا كانت هناك طريقة أفضل.

JQuery UI له تأثير "تسليط الضوء" يوضح ما أريد إنجازه (على الرغم من أنني أريد أن يكون لي أبطأ قليلاً). فقط اذهب هنا إلى jQuery UI Effect, ، حدد "تسليط الضوء" من المربع المنسدلة في النافذة ، وانقر فوق "Run Effect".

يحرر
اضطررت للذهاب مع الحل الخاص بي بناءً على وقتي وقيود الموارد ، لكن مربعات النص لا تدعم الألوان الشفافة كما ذكر هانز باسانت. لذلك ، استخدمت مؤقتًا للتوقف الذاتي يزيد من قيم R و G و B حتى يصبح التحكم أبيض تمامًا (R = 255 ، G = 255 ، B = 255) ؛

تحرير 2
انتهى من إعادة ترميز حدث الفلاش كوسيلة تمديد باستخدام تباين في حل جورج جونستون بعد تحديثه إلى .NET 4.0. هذا حل أنظف كثيرًا ، وأشعر ، وطريقة التمديد تجعله متاحًا تلقائيًا لأي شخص using هو - هي.

هل كانت مفيدة؟

المحلول

يمكنك تدوير مؤشر ترابط منفصل لكل مربع نص وامض حتى لا يمنع النموذج الخاص بك من استخدامه أثناء وميض مربع النص (s). تأكد من استدعاء النموذج الخاص بك لأن الغزل من الخيط سيتطلب خيط متقاطع. الحل الكامل أدناه.

private void Form1_Load(object sender, EventArgs e)
{
    // textBox1 is the control on your form.
    // 1000 is the total interval between flashes
    // Color.LightBlue is the flash color
    // 10 is the number of flashes before the thread quits.
    Flash(textBox1, 1000,Color.LightBlue,10);
    Flash(textBox2, 1500,Color.Green,10);
    Flash(textBox3, 100,Color.Red,10);
    Flash(textBox4, 500,Color.Brown,10);
    Flash(textBox5, 200,Color.Pink,10);
}

public void Flash(TextBox textBox, int interval, Color color, int flashes)
{
    new Thread(() => FlashInternal(textBox, interval, color, flashes)).Start();
}

private delegate void UpdateTextboxDelegate(TextBox textBox, Color originalColor);
public void UpdateTextbox(TextBox textBox, Color color)
{
    if (textBox.InvokeRequired)
    {
        this.Invoke(new UpdateTextboxDelegate(UpdateTextbox), new object[] { textBox, color });
    }
    textBox.BackColor = color;
}

private void FlashInternal(TextBox textBox, int interval, Color flashColor, int flashes)
{
    Color original = textBox.BackColor;
    for (int i = 0; i < flashes; i++)
    {

        UpdateTextbox(textBox, flashColor);
        Thread.Sleep(interval/2);
        UpdateTextbox(textBox, original);
        Thread.Sleep(interval/2);
    }
}

هذا يتجنب الاضطرار إلى وضع عناصر تحكم المؤقت الداعمة في النموذج الخاص بك.

نصائح أخرى

قد يبدو WPF مثاليًا لهذا الغرض. يمكنك بنائه في WPF واستخدامه في WinForms كمضيف. أضف عنصر تحكم مستخدم WPF جديد ، وهذا في XAML:

<UserControl x:Class="WpfControlLibrary1.UserControl1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="20" d:DesignWidth="300">
<TextBox>
    <TextBox.Triggers>
        <EventTrigger RoutedEvent="TextBox.TextChanged">
            <BeginStoryboard>
                <Storyboard AutoReverse="False" BeginTime="0" >
                    <DoubleAnimation Storyboard.TargetName="Foo"
                                 Storyboard.TargetProperty="Opacity"
                                 From="0" To="1" Duration="0:0:1"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </TextBox.Triggers>
    <TextBox.Background>
        <SolidColorBrush Opacity="1" x:Name="Foo" Color="LightGray" />
    </TextBox.Background>
</TextBox>
</UserControl>

(يمكن أن يقوم ببعض العمل ، لكنه بداية). هناك لديك - مربع نص رائع :)

قم بإنشاء الحل ، وسيظهر عنصر جديد في Toolbox - فقط سحب وإسقاط إلى النموذج الخاص بك ، وسيتم استضافة WPF داخل عنصر ElementHost. إن جماله هو أنه يمكنك فعل الكثير في الأساليب المرئية في WPF ، ومع ذلك ، يتم استضافته WPF الذي يضيف وزنًا معينًا إلى الحل الخاص بك ...

اشتق فصلك من TextBox. أعطها Flash() الطريقة التي تبدأ الوميض. فقط تغيير BackColor إلى لون الباستيل. لا تستخدم ألفا ، وهذا لا يعمل على TextBox.

يجب أن يكون لديك جميع مثيلات هذه الفئة مشاركة مؤقتًا مشتركًا حتى تومض في نفس الوقت. اجعل الموقت ثابتًا ومرجعًا لعدد الحالات التي لديك. أضف ما يصل في المنشئ ، أسفل في Dispose(bool) تجاوز.

إذا تم تعيينك على طرقك في استخدام WinForms ، ثم مع معرفتي المحدودة ، يمكنني أن أقترح الحصول على ضوابط من طرف ثالث للمساعدة. عدد قليل من Teleerik و ComponentOne. إذا كنت تريد شيئًا ما يعجبك ، فيمكنك الاستفادة من WPF ، وتطوير الرسوم المتحركة المخصصة في XAML (والتي أعتقد أنها تشبه Silverlight XAML في إنشاء حالات واجهة المستخدم والرسوم المتحركة). بخلاف هذه ، أنا خارج عن التجربة لتقديم أي مساعدة.

اعتمادًا على تطبيقك ، تتمثل إحدى الطرق المبهجة في القيام بذلك عن طريق تغيير Gamma لصورة مربع النص الخاص بك. هذا بالطبع يعتمد على مقدار الوقت الذي تريد وضعه فيه ، لكنه بالتأكيد ممكن. لقد رأيت العديد من البرامج التعليمية حول كيفية ضبط جاما الصورة والحصول على صورة لعنصر التحكم الخاص بك أمر تافهة.

ومع ذلك ، أعتقد أيضًا أنه من غير التافهة ضبط الألوان الخلفية لمربع النص على شفاف. من صياغتك ، لا يمكنني إلا أن أخمن أنك تريد تلاشي اللون من الألوان الخلفية الأساسية للسيطرة إلى BackColor "مربع النص" ، وفي هذه الحالة تكون المشكلة تافهة مرة أخرى. ولكن إذا كان لديك صورة خلفية ، فيجب عليك إعادة النظر. ومع ذلك ، لا يزال ذلك ممكنًا ويمكنني أن أحفر رابطًا لك عن كيفية القيام بذلك إذا كان هذا ما تحاول تحقيقه.

سيكون الحل Easy Quick'n هو تحريك لون النص ولون الخلفي من اللون الأبيض إلى لونك المقدمة الحالي.

إذا لم تكن مهتمًا باستخدام الخيوط ، فستبقي على إجابة جورج جونستون هنا على النحو التالي:

private bool CurrentlyFlashing = false;
private void FlashInternal(TextBox textBox, int interval, Color flashColor, int flashes)
{
    if (CurrentlyFlashing) return;

    CurrentlyFlashing = true;
    Color original = textBox.BackColor;
    for (int i = 0; i < flashes; i++)
    {
        UpdateTextbox(textBox, flashColor);
        Application.DoEvents();
        Thread.Sleep(interval / 2);
        UpdateTextbox(textBox, original);
        Application.DoEvents();
        Thread.Sleep(interval / 2);
    }
    CurrentlyFlashing = false;
}
private delegate void UpdateTextboxDelegate(TextBox textBox, Color originalColor);
public void UpdateTextbox(TextBox textBox, Color color)
{
    if (textBox.InvokeRequired)
    {
        this.Invoke(new UpdateTextboxDelegate(UpdateTextbox), new object[] { textBox, color });
    }
    textBox.BackColor = color;
}

سؤال قديم جدًا ، لكنني اعتقدت أنني سأقوم بالتحديث بإجابة أكثر حداثة ، لأن Async/Await لم يكن موجودًا في عام 2010 عندما أجاب آخر الإجابات

أقوم أيضًا بتحديثه لاستخدام فلاش واحد يتلاشى بشكل جيد بدلاً من وميض يحفز النوبة ، وقام بتغيير الكتابة بحيث لا يتم استخدامه على مربعات النص.

نظرًا لأنه يستخدم Async/في انتظار ، فمن الآمن القيام به على الخيط الرئيسي دون الحاجة إلى المندوب أو InvokeRequired التحقق من. حتى إذا قمت بتعيين مدة التلاشي على شيء طويل ، فستظل قادرًا على التفاعل مع التطبيق أثناء تشغيل حلقة التلاشي.

    private bool CurrentlyFlashing = false;
    private async void FlashControl(Control control)
    {
        Color flashColor = Color.Yellow;

        float duration = 500; // milliseconds
        int steps = 10;
        float interval = duration / steps;

        if (CurrentlyFlashing) return;
        CurrentlyFlashing = true;
        Color original = control.BackColor;

        float interpolant = 0.0f;
        while (interpolant < 1.0f)
        {
            Color c = InterpolateColour(flashColor, original, interpolant);
            control.BackColor = c;
            await Task.Delay((int) interval);
            interpolant += (1.0f / steps);
        }

        control.BackColor = original;

        CurrentlyFlashing = false;
    }

    public static Color InterpolateColour(Color c1, Color c2, float alpha)
    {
        float oneMinusAlpha = 1.0f - alpha;
        float a = oneMinusAlpha * (float)c1.A + alpha * (float)c2.A;
        float r = oneMinusAlpha * (float)c1.R + alpha * (float)c2.R;
        float g = oneMinusAlpha * (float)c1.G + alpha * (float)c2.G;
        float b = oneMinusAlpha * (float)c1.B + alpha * (float)c2.B;
        return Color.FromArgb((int)a, (int)r, (int)g, (int)b);
    }

لقد ترسمت اللون والتوقيت بشدة بدلاً من تعريضهم كمعلمات وظيفية كما فعل المستجيبون الآخرون ، لأنني عادةً ما أريد أن يكونوا متماثلين في طلبي إذا قمت بإعادة استخدام هذا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top