Je veux faire une séquence d'événements chronométrés pour une lumière clignotante de code morse. Le programme doit pouvoir être utilisé pendant que le voyant clignote.

Il y aura donc une longue pause au début, puis il commencera à clignoter des signes longs et courts avec de petites pauses entre les deux, puis recommencera.

Exemple de séquence

  • Éteint 3000ms
  • Lumière sur 1200ms
  • Éteignez 500ms
  • Lumière sur 400ms
  • Éteignez 500ms
  • Lumière sur 1200ms
  • Éteignez 500ms
  • Lumière sur 400ms
  • recommencer à nouveau

J'ai essayé ce code mais il ne fait que geler le programme

private void Morse()
{
    System.Timers.Timer MorseCode = new System.Timers.Timer(3000);
    MorseCode.Elapsed += new ElapsedEventHandler(long);
    MorseCode.Elapsed += new ElapsedEventHandler(short);
    MorseCode.Elapsed += new ElapsedEventHandler(long);
    MorseCode.Elapsed += new ElapsedEventHandler(short);

    void short(object sender, ElapsedEventArgs e)
    {
        MorseCode.Elapsed += new ElapsedEventHandler(ColorChange);
        MorseCode.Interval = 400;
        MorseCode.Elapsed += new ElapsedEventHandler(ColorChange);
        MorseCode.Interval = 500;
    }
    void long(object sender, ElapsedEventArgs e)
    {
        MorseCode.Elapsed += new ElapsedEventHandler(ColorChange);
        MorseCode.Interval = 1200;
        MorseCode.Elapsed += new ElapsedEventHandler(ColorChange);
        MorseCode.Interval = 500;
    }
    void ColorChange(object sender, ElapsedEventArgs e)
    {
        if(BlinkLight.BackColor == Color.Gray)
        {
            BlinkLight.BackColor = Color.DodgerBlue;
        }
        else
        {
            BlinkLight.BackColor = Color.Gray;
        }
    }    
}

Alors, comment puis-je créer une séquence avec des horaires différents pour une lumière clignotante?

0
Denji 20 nov. 2018 à 13:40

3 réponses

Meilleure réponse

Vous pouvez utiliser la bibliothèque parallèle de tâches pour cela, elle est incluse dans .NET 4 et plus. Cela produira un code lisible comme celui-ci:

private void Morse()
{
    BlinkShort().ContinueWith(          //
        BlinkShort).ContinueWith(       //  S
        BlinkShort).ContinueWith(       //
        BlinkLong).ContinueWith(        //
        BlinkLong).ContinueWith(        //  O
        BlinkLong).ContinueWith(        // 
        BlinkShort).ContinueWith(       //
        BlinkShort).ContinueWith(       //  S
        BlinkShort);                    // 
}

Exemple d'implémentation de méthodes d'assistance:

private Task BlinkShort(Task previousTask = null)
{
    var action = new Action(() =>
    {
        SetColorSafe(true);
        Task.Delay(400).Wait();
        SetColorSafe(false);
        Task.Delay(500).Wait();
    });
    var t = Task.Run(action);
    if (previousTask != null) // already threaded
    {
        t.Wait();
    }

    return t;
}
private Task BlinkLong(Task previousTask = null)
{
    var action = new Action(() =>
    {
        SetColorSafe(true);
        Task.Delay(1200).Wait();
        SetColorSafe(false);
        Task.Delay(500).Wait();
    });
    var t = Task.Run(action);
    if (previousTask != null) // already threaded
    {
        t.Wait();
    }

    return t;
}

private void SetColorSafe(bool on)
{
    if (InvokeRequired)
    {
        Invoke(new Action(() => {
            SetColorSafe(on);
        }));
        return;
    }
    if (on)
    {
        BackColor = Color.DodgerBlue;
    }
    else
    {
        BackColor = Color.Gray;
    }
}
0
Fixation 20 nov. 2018 à 12:03

Utilisez le cadre réactif de Microsoft pour cela - NuGet "System.Reactive.Windows.Forms".

Ensuite, vous pouvez le faire:

int[] timings = new [] { 3000, 1200, 500, 400, 500, 1200, 500, 400 };

IObservable<System.Drawing.Color> sequence =
    Observable
        .Generate(
            0,
            x => x < timings.Length,
            x => x + 1,
            x => x % 2 == 1 ? System.Drawing.Color.DodgerBlue : System.Drawing.Color.Gray,
            x => TimeSpan.FromMilliseconds(timings[x]));

IDisposable subscription =
    sequence
        .Repeat()
        .ObserveOn(BlinkLight)
        .Subscribe(color => BlinkLight.BackColor = color);
0
Enigmativity 20 nov. 2018 à 11:08

J'aime la solution d'Enigmativity. Si vous connaissez System.Reactive, c'est un choix Google.

C'est une solution simple utilisant une tâche asynchrone.
Je passe à la méthode asynchrone:
- un List<Tuple<int, int>> qui représente les espaces et les durées des signaux
- une référence Control qui servira de sortie visuelle
- un CancellationToken, utilisé pour signaler quand la tâche doit être terminée.

La tâche peut être annulée, puis recommencer avec la même séquence ou une nouvelle.
Si elle n'est pas annulée, la tâche se poursuivra indéfiniment, jouant la séquence en cours.
Ici, j'utilise un bouton pour démarrer la tâche. Je pourrais être n'importe quoi d'autre.

Notez que j'ai un peu modifié la séquence et les horaires. La pause entre chaque itération de séquence est à la fin de la séquence, donc il démarre le signal immédiatement, puis il le met en pause après chaque séquence est exécutée.

Lorsqu'une demande d'annulation est émise, la tâche terminera la séquence avant l'annulation:
if (token.IsCancellationRequested) return; n'est vérifié qu'une fois la séquence terminée, pour éviter de jouer avec les horaires. Mais cela pourrait être modifié pour vérifier l'annulation après chaque longue pause.

CancellationTokenSource source;
CancellationToken token;

private void button1_Click(object sender, EventArgs e)
{
    if (source != null)
    {
        source.Cancel();
        source.Dispose();
        source = null;
        return;
    }

    source = new CancellationTokenSource();
    token = source.Token;
    List<Tuple<int, int>> MorseCodeSequence = new List<Tuple<int, int>>()
    {
        new Tuple<int, int>(1200, 200),
        new Tuple<int, int>(400, 200),
        new Tuple<int, int>(1200, 200),
        new Tuple<int, int>(400, 2000)
    };

    Task.Run(()=> MorseSequence(MorseCodeSequence, this.btnMorse, token));
}

public async Task MorseSequence(List<Tuple<int, int>> MorseSequence, Control MorseCodeOutputObject, CancellationToken token)
{
    while (true)
    {
        foreach (Tuple<int, int> MorseTiming in MorseSequence)
        {
            MorseCodeOutputObject.BeginInvoke(new MethodInvoker(() =>
                { MorseCodeOutputObject.BackColor = Color.Cyan; }));
            await Task.Delay(MorseTiming.Item1);
            MorseCodeOutputObject.BeginInvoke(new MethodInvoker(() =>
                { MorseCodeOutputObject.BackColor = Color.Gray; }));
            await Task.Delay(MorseTiming.Item2);
        }
        if (token.IsCancellationRequested) return;
    };
}

La séquence SOS

List<Tuple<int, int>> SOSMorseSequence = new List<Tuple<int, int>>()
{
    new Tuple<int, int>(400, 200),
    new Tuple<int, int>(400, 200),
    new Tuple<int, int>(400, 300),
    new Tuple<int, int>(1200, 200),
    new Tuple<int, int>(1200, 200),
    new Tuple<int, int>(1200, 300),
    new Tuple<int, int>(400, 200),
    new Tuple<int, int>(400, 200),
    new Tuple<int, int>(400, 2000),
};
0
Jimi 20 nov. 2018 à 13:35