Zatrzymanie wątku, aby mógł działać od nowa, od zera.

0

Witam!
Mam taki oto kod:

 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;

namespace WindowsFormsApplication17
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        void watek1()
        {
            for (int a1 = 5; a1 >= 0; a1--)
            {
                for (int b1 = 59; b1 >= 0; b1--)
                {
                    if (b1 < 10)
                    {
                        label1.Invoke(new Action(delegate() { label1.Text = a1.ToString() + ":0" + b1.ToString(); }));
                    }
                    else
                    {
                        label1.Invoke(new Action(delegate() { label1.Text = a1.ToString() + ":" + b1.ToString(); }));
                    }
                    Thread.Sleep(1000);
                    if (a1 == 0 && b1 == 0)
                    {
                        label13.Invoke(new Action(delegate() { label13.Text = "Zrobione!"; }));
                    }
                }
            }
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F2)
            {
                Thread thread1;
                thread1 = new Thread(watek1);
                thread1.IsBackground = true;
                if (thread1.IsAlive == true)
                {
                    thread1.Interrupt();
                    thread1.Abort();
                    thread1.Start();
                }
                else
                {
                    thread1.Start();
                }
            }
        }
    }
}

I mam pytanie, czemu nie działają funkcje thread1.Interrupt() oraz thread1.Abort()? Wątek startuje od nowa, jednak liczy 2 razy, po dwóch kliknięciach klawisza F2, label1 mruga, zmienia liczby i gdy drugie naciśnięcie nastąpi po np. 30 sekundach, label 13 zmienia się na Zrobione po upłynięciu 5 minut od pierwszego naciśnięcia.

Przy okazji tego wątku, jak zrobić, aby program odczytywał naciśnięcie klawisza F2 nawet, jeśli nie jest na nim aktualnie focus? Czyli moja forma jest nawet zminimalizowana, ale po naciśnięciu F2 odliczanie się rozpoczyna.

0

bo w funkcji key_down za każdym razem tworzysz nowy wątek

thread1 = new Thread(watek1);

po czym dopiero sprawdzasz czy działa, zanim go uruchomisz

IsAlive zawsze będzie false bo referencję do odpalonego wątku już straciłeś, a nowy nie został jeszcze uruchomiony.

Użycie wątku w tym przypadku i tak jest bezsensowne - całą pracę wątek i tak deleguje do wątku głównego - jedyną pracę jaką wykonuje wątek sam w sobie to Sleep...
Dużo lepszym rozwiązaniem będzie więc tutaj użycie najprostszego Timera.
Poza tym że kod będzie czystszy i logiczniejszy, to Timer łatwiej zapauzować, wznowić i zresetować stan zmiennych na których operuje.

Jeśli chcesz żeby klawisz działał poza aplikacją to musisz zarejestrować w systemie skrót klawiszowy, jako okno rodzica podając okno pulpitu.
Google: c# global hotkey

0

tak, tylko gdy próbowałem tworzyć wątek gdzieś wcześniej, to za każdym razem w tej funkcji nie widzi thread1. A robię to na wątkach, ponieważ takich odliczań będzie kilka, będą działać różnie, w różnych momentach startowane.

0
NoWay napisał(a):

tak, tylko gdy próbowałem tworzyć wątek gdzieś wcześniej, to za każdym razem w tej funkcji nie widzi thread1. A robię to na wątkach, ponieważ takich odliczań będzie kilka, będą działać różnie, w różnych momentach startowane.

co znaczy nie widzi? podaj kod
poza tym nie możesz użyć tego samego wątku dwa razy - raz wystartowany wątek może być jedynie zatrzymany i wyrzucony; nie da się ich odpalić drugi raz
możesz po prostu przesłać do wątku informację żeby się zresetował - poprzez zwyczajną zmienną volatile na którą wątek zareaguje tak że po prostu zresetuje stan swoich zmiennych

i nic nie szkodzi że odliczań będzie więcej - timerów też może być więcej a zdecydowanie lepiej się nadają tutaj

0

już sobie poradziłem z tym. :) wszystko działa jak miało działać, zostało tylko globalnie zadeklarować klawisz.

0
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;

namespace WindowsFormsApplication17
{
    public partial class Form1 : Form
    {
        Thread thread1;

        public Form1()
        {
            InitializeComponent();

            thread1 = new Thread(watek1);
            thread1.IsBackground = true;
}

        void watek1()
        {
            for (int a1 = 2; a1 >= 0; a1--)
            {
                for (int b1 = 59; b1 >= 0; b1--)
                {
                    if (b1 < 10)
                    {
                        label1.Invoke(new Action(delegate() { label1.Text = a1.ToString() + ":0" + b1.ToString(); }));
                    }
                    else
                    {
                        label1.Invoke(new Action(delegate() { label1.Text = a1.ToString() + ":" + b1.ToString(); }));
                    }
                    Thread.Sleep(100);
                    if (a1 == 0 && b1 == 0)
                    {
                        label13.Invoke(new Action(delegate() { label13.Text = "Zrobione!"; }));
                    }
                }
            }
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F2)
            {
                if (thread1.IsAlive)
                {
                    thread1.Abort();
                    thread1 = new Thread(watek1);
                    thread1.IsBackground = true;
                    thread1.Start();
                }
                else
                {
                    thread1.Start();
                }
            }
        }
 }
}

w taki sposób ja to zrobiłem.

0

na timerach:

namespace WindowsFormsApplication7
{
    public partial class Form1 : Form
    {
        Timer timer1;

        public Form1()
        {
            InitializeComponent();

            timer1 = new Timer { Interval = 100 };
            timer1.Tick += timer_Tick;
        }

        void timer_Tick(object sender, EventArgs e)
        {
            var left = (TimeSpan)(sender as Timer).Tag - TimeSpan.FromSeconds(1);

            label1.Text = left.ToString(@"mm\:ss");

            if (left <= TimeSpan.Zero)
            {
                label13.Text = "Zrobione!";
                (sender as Timer).Stop();
            }

            (sender as Timer).Tag = left;
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F2)
            {
                timer1.Stop();
                timer1.Tag = TimeSpan.FromMinutes(3);
                timer1.Start();
            }
        }
    }
}

warto wspomnieć że obie powyższe metody nie będą całkowicie dokładnie odmierzać czasu i różnica może być widoczna po kilku godzinach

1 użytkowników online, w tym zalogowanych: 0, gości: 1