Stopwatch changing button text in c#

2019-08-22 04:07发布

问题:

Basically, I've got multiple button in my Form, and I want for it show a Stopwatch in the button.Text when the button is pressed. (Button is modified to be a toggle button.) and to stop and reset the timmer when the button is toggled off. Simple enough it seemed but because I have multiple buttons that could be pressed in any order, and I don't know anything about threading, this seems to be much more difficult that I presumed.

My origional intent was to have a function that constantly runs every second and interates a interager only if the button is pressed using this code:

public void Jogger()//purpose is to step up time[0] every second only when a button is on.
    {
        while (true)
        {
            for (int i = 0; i < 16; i++)
            {
                if (btnstat[i])
                    time[i]++;
            }
            Thread.Sleep(1000);
        }
    }

Problem is, I don't know threading so when I call the function, its stuck doing this and only this.

Either way, once this is called, all i do us call my update function that updates all the buttons including the button.Text which displays the time[0]; (array built around buttons)

Is their a better way of doing this that doesn't cause so much CPU use and/or simply works?

Thanks for all the help! -John Ivey

回答1:

Assuming you using checkbox with property Button = Appearence, in event handler for CheckedChanged:

private void CheckBoxCheckedChanged(object sender, EventArgs e)
{
    CheckBox checkBox = (CheckBox) sender;

    if (checkBox.Checked)
    {
        Timer timer = new Timer {Interval = 1000};
        timer.Tick += Jogger;
        timer.Start();
        timer.Tag = new CheckboxCounter {CheckBox = checkBox, Time = 0};
        checkBox.Tag = timer;
    }
    else
    {
        Timer timer = checkBox.Tag as Timer;
        if (timer != null)
        {
            timer.Tag = null;
            timer.Stop();
            timer.Dispose();
            checkBox.Tag = null;
        }
    }
}

Change your Jogger function:

private void Jogger(object a_sender, EventArgs a_eventArgs)
{
    Timer timer = (Timer) a_sender;
    CheckboxCounter data = (CheckboxCounter)timer.Tag;
    data.Time++;
    data.CheckBox.Text = data.Time.ToString();
}

You also need some simple class to store checkbox and current time:

class CheckboxCounter
{
    public CheckBox CheckBox;

    public int Time;
}

Then you can add any number of checkboxes and just set event CheckedChanged to CheckBoxCheckedChanged.



回答2:

Try this out. After re-building or running, you should have the new "ButtonTimer" at the top of your ToolBox. Drop a couple on your Form, run it, and see what happens when you click them. Right click them to "Reset" them:

public class ButtonTimer : CheckBox
{

    private System.Windows.Forms.Timer Tmr = new System.Windows.Forms.Timer();
    private System.Diagnostics.Stopwatch SW = new System.Diagnostics.Stopwatch();

    public ButtonTimer()
    {
        this.Tmr.Interval = 500;
        this.Tmr.Tick += new EventHandler(tmr_Tick);
        this.Appearance = System.Windows.Forms.Appearance.Button;
        this.CheckedChanged += new EventHandler(ButtonTimer_CheckedChanged);

        ContextMenuStrip cms = new ContextMenuStrip();
        ToolStripItem tsi = cms.Items.Add("Reset");
        tsi.Click += new EventHandler(tsi_Click);
        this.ContextMenuStrip = cms;
    }

    protected override void OnLayout(LayoutEventArgs levent)
    {
        base.OnLayout(levent);
        this.Text = TimeSpan.Zero.ToString(@"hh\:mm\:ss");
    }

    private void ButtonTimer_CheckedChanged(object sender, EventArgs e)
    {
        if (this.Checked)
        {
            this.SW.Start();
            this.Tmr.Start();
        }
        else
        {
            this.SW.Stop();
            this.Tmr.Stop();
        }
    }

    private void tmr_Tick(object sender, EventArgs e)
    {
        this.UpdateTime();
    }

    private void UpdateTime()
    {
        this.Text = this.SW.Elapsed.ToString(@"hh\:mm\:ss");
    }

    private void tsi_Click(object sender, EventArgs e)
    {
        if (this.SW.IsRunning)
        {
            SW.Restart();
        }
        else
        {
            SW.Reset();
        }
        this.UpdateTime();
    }

}


回答3:

Application.DoEvents() for simplicity put inside loop . . but it is advisable to start to lean threading . you will just learn how to start thread and how make cross thread safe call Next simple will be to use backgroundworker . look this http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

ok here is thread solution also as you wanted . Tested too . as a stop variable i used Tag. But u can inherit button to make state button.it be more clear way . And below code will use one thread per button . So u should make it in one thread to make it better solution . You can modify this code to do all checkings inside one thread . For this you start thread once can make delegate for attaching dinamically count function for each button or you can pass buttons before . With one word there are more than one way to do it. Good luck

this.button1.Click += new System.EventHandler(this.button_Click);
this.button2.Click += new System.EventHandler(this.button_Click);
...and so on
  private void button_Click(object sender, EventArgs e)
        {
           Thread x= new Thread(new ParameterizedThreadStart(Jogger2));
            x.Start(sender);

        }


        private void button_Click(object sender, EventArgs e)
    {
        Button mybtn=sender as Button;
        if((string)mybtn.Tag=="start"){
            mybtn.Tag ="";
            return;
         }
        mybtn.Tag = "start";
       Thread x= new Thread(new ParameterizedThreadStart(Jogger2));
        x.Start(sender);

    }


    private bool  setResult(object obj,string text)
    { 
        if (this.textBox1.InvokeRequired)
        {
            Func<Button,string, bool > d = new Func<Button,string,bool >(setResult);
            return (bool)this.Invoke(d,obj,text);

        }
        else
        {
            Button btn=obj  as Button;

            if (btn != null)
            {
                btn.Text = text;
                if ((string)btn.Tag !="start") return false;
            }
            return true;
        }
    }
    private void Jogger2(object mybtn)
    {
        int ii = 0; 
        while (true)
        {
            Thread.Sleep(1000);
                //replace with your code
                ii += 1;
                if (!setResult(mybtn, ii.ToString())) break; 

        }

    }