当前位置:编程学习 > C#/ASP.NET >>

windows窗体应用程序中怎么实现一个按钮控制另一个按钮对应事件?

如题
楼主对窗体应用程序不是很懂。现在我在窗体中有两个button,一个是“start”,一个是“stop”。start的对应事件是一个死循环。现在我想用点击start开始执行,点击stop让start的事件停止运行。程序如下:



但是第33行有错误,“字符初始值无法引用非静态字段、方法或属性SThread”。
求大神指教。怎么才能实现一个按钮控制另一个按钮对应事件。          --------------------编程问答-------------------- 在线程的那个类中定义一个共有bool变量,
主程序改变它,线程每次循环都判断下,如果它被设置,就退出。 --------------------编程问答-------------------- using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            SThread.SetTextAction = SetText;
            SThread.form = this;
            isPause = true;
            isStop = true;
        }
        private static Boolean isPause = true;
        private static Boolean isStop = false;
        private SubThread SThread = new SubThread();
        private Thread thread;
        public void SetText(String text)
        {
            this.Text = text;
        }
        public class SubThread
        {
            public Form form;
            public Action<String> SetTextAction;
            public void SubThreadStartFunction()
            {
                int i=0;
                do
                {
                    if (!isPause)
                    {
                        i++;
                        form.Invoke(SetTextAction, new Object[1] { i.ToString() });
                    }
                } while (!isStop);
            }
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (isStop)
            {
                isStop = false;
                thread = new Thread(SThread.SubThreadStartFunction);
                thread.Start();
            }
            isPause = false;
        }

        private void buttonPause_Click(object sender, EventArgs e)
        {
            isPause = true;
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            isStop=true;
        }
    }
} --------------------编程问答-------------------- 先根据你的代码添加了按钮控制
public static bool IsRunning = true;
public class SubThread
{
public void SubThreadFunc()
{
int i = 0;
while(Form1.IsRunning)
{
i++;
Console.WriteLine("子程序正在运行……{0}",i);
}
}
SubThread SThread = new SunThread();
Thread ThreadS = new Thread(new ThreadStart(SThread.SubThreadFunc));
}

private void txtBoxStart_TextChanged(object sender, EventArgs e)
{
IsRunning = true;
Thread ThreadS = new Thread(new ThreadStart(SThread.SubThreadFunc));
}

private void txtBoxStart_TextChanged(object sender, EventArgs e)
{
IsRunning = false;
}

然后根据你的代码功能做了一些修改
private bool IsRunning = false;
private Thread SubThread;

public Form1()
{
InitializeComponent();
SubThread = new Thread(SubThreadFunc);
SubThread.Start();
}

private void SubThreadFunc()
{
int i = 0;
while(true)
{
if(IsRunning)
{
i++;
Console.WriteLine("子程序正在运行……{0}",i);
}
}
}

private void txtBoxStart_TextChanged(object sender, EventArgs e)
{
IsRunning = true;
}

private void txtBoxStart_TextChanged(object sender, EventArgs e)
{
IsRunning = false;
}

还有另一种改法
private bool IsRunning = false;
private Thread SubThread;

public Form1()
{
InitializeComponent();
SubThread = new Thread(SubThreadFunc);
}

private void SubThreadFunc()
{
int i = 0;
while(IsRunning)
{
i++;
Console.WriteLine("子程序正在运行……{0}",i);
}
}

private void txtBoxStart_TextChanged(object sender, EventArgs e)
{
IsRunning = true;
SubThread.Start();
}

private void txtBoxStart_TextChanged(object sender, EventArgs e)
{
if (SubThread != null)
{
SubThread.Abort();
}
IsRunning = false;
}
--------------------编程问答-------------------- 抱歉,忘了把txtBoxStart_TextChanged改成txtBoxStop_TextChanged
private void txtBoxStop_TextChanged(object sender, EventArgs e)
{
IsRunning = false;
if (SubThread != null)
{
SubThread.Abort();
}
}
--------------------编程问答--------------------
引用 楼主 sdqdpdldyq 的回复:
如题
楼主对窗体应用程序不是很懂。现在我在窗体中有两个button,一个是“start”,一个是“stop”。start的对应事件是一个死循环。现在我想用点击start开始执行,点击stop让start的事件停止运行。程序如下:



但是第33行有错误,“字符初始值无法引用非静态字段、方法或属性SThread”。
求大神指教。怎么才能实现一个按钮控制另一个按钮对应事件。         


变量、字段和方法在初始化的时候不能用动态的变量初始化。你可以改为静态变量,或者改在类的构造函数中去初始化。
具体原理我也不是很清楚,大致是用变量初始化变量,很难检查异常,并可能产生相互依赖。
例如:
int a=b;
int b=a;
这种初始化没有任何意义,但从语法角度,如果允许使用变量初始化变量,则无法避免这种情况发生。
事实上,某些语言甚至不能完全地支持变量的初始化。比如VB6。
我上面的例子是在构造函数中完成初始化的。
参考:http://blog.csdn.net/yl_99/article/details/8472789。 --------------------编程问答--------------------
引用 2 楼 u012592437 的回复:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            SThread.SetTextAction = SetText;
            SThread.form = this;
            isPause = true;
            isStop = true;
        }
        private static Boolean isPause = true;
        private static Boolean isStop = false;
        private SubThread SThread = new SubThread();
        private Thread thread;
        public void SetText(String text)
        {
            this.Text = text;
        }
        public class SubThread
        {
            public Form form;
            public Action<String> SetTextAction;
            public void SubThreadStartFunction()
            {
                int i=0;
                do
                {
                    if (!isPause)
                    {
                        i++;
                        form.Invoke(SetTextAction, new Object[1] { i.ToString() });
                    }
                } while (!isStop);
            }
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (isStop)
            {
                isStop = false;
                thread = new Thread(SThread.SubThreadStartFunction);
                thread.Start();
            }
            isPause = false;
        }

        private void buttonPause_Click(object sender, EventArgs e)
        {
            isPause = true;
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            isStop=true;
        }
    }
}

“form.Invoke(SetTextAction, new Object[1] { i.ToString() });”这一句不知道是做什么用的呀?如果我的SetTextAction有两个参数,应该怎么写呢? --------------------编程问答--------------------
引用 6 楼 sdqdpdldyq 的回复:
Quote: 引用 2 楼 u012592437 的回复:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            SThread.SetTextAction = SetText;
            SThread.form = this;
            isPause = true;
            isStop = true;
        }
        private static Boolean isPause = true;
        private static Boolean isStop = false;
        private SubThread SThread = new SubThread();
        private Thread thread;
        public void SetText(String text)
        {
            this.Text = text;
        }
        public class SubThread
        {
            public Form form;
            public Action<String> SetTextAction;
            public void SubThreadStartFunction()
            {
                int i=0;
                do
                {
                    if (!isPause)
                    {
                        i++;
                        form.Invoke(SetTextAction, new Object[1] { i.ToString() });
                    } 
                } while (!isStop);
            }
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (isStop)
            {
                isStop = false;
                thread = new Thread(SThread.SubThreadStartFunction);
                thread.Start();
            }
            isPause = false;
        }

        private void buttonPause_Click(object sender, EventArgs e)
        {
            isPause = true;
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            isStop=true;
        }
    }
}

“form.Invoke(SetTextAction, new Object[1] { i.ToString() });”这一句不知道是做什么用的呀?如果我的SetTextAction有两个参数,应该怎么写呢?


if (!isPause){}中的语句就是你要在后台执行的语句。
如果这里的语句不涉及对窗口线程的操作(对窗口、控件和属性的操作),那么你可以直接在里面写。
如果你想在附属线程操作窗口在组件(比如反馈进度,我这里更改窗口标题来显示循环的进度),则涉及跨线程访问窗口控件。我这里使用form.Invoke,实现在form的线程调用一个函数。在这个函数里操作窗口控件。
Invoke方法有两个参数。一个是要在窗口线程中操作的函数的委托(相当于函数的指代),另一个是数组,是这个函数的参数。
如果你有两个参数,需要Invoke(xxx,new Object[2]{参数1,参数2})
相应的,函数委托变量的声明也要改成 Action <参数1的类型,参数2的类型> xxx
具体的执行函数,也要改成两个参数的。

在新线程里,绝大部分操作都应该不是直接针对窗口和控件的,否则这个线程就没有意义。
但如果要报告进度,也许需要不定期的调用,这才会用到窗口的Invoke方法。

对于你留言提到的:
您好,您回复我的帖子http://bbs.csdn.net/topics/390671805?page=1#post-396363023。当我把SetText()的定义改为以下几句,为什么点击“开始”之后,就再也不能点其他按钮呢? this.Text = Convert.ToString(1); Thread.Sleep(5000); 这两句

你不要在Invoke方法调用的委托所指代的函数中执行 Thread.Sleep(5000)。这相当于把窗口线程卡死了。(form.Invoke方法所在的 form的线程(主线程) 被委托SetTextAction 所指代的 SetText函数中的sleep语句给挂起了)
你可能需要这么改
if (!isPause)
{
    i++;
    form.Invoke(SetTextAction, new Object[1] { i.ToString() });
    Thread.Sleep(5000); 

这才是在新的线程中休眠,并定期通过Invoke方法访问窗口的标题属性报告进度。 --------------------编程问答--------------------
引用 7 楼 u012592437 的回复:
Quote: 引用 6 楼 sdqdpdldyq 的回复:

Quote: 引用 2 楼 u012592437 的回复:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            SThread.SetTextAction = SetText;
            SThread.form = this;
            isPause = true;
            isStop = true;
        }
        private static Boolean isPause = true;
        private static Boolean isStop = false;
        private SubThread SThread = new SubThread();
        private Thread thread;
        public void SetText(String text)
        {
            this.Text = text;
        }
        public class SubThread
        {
            public Form form;
            public Action<String> SetTextAction;
            public void SubThreadStartFunction()
            {
                int i=0;
                do
                {
                    if (!isPause)
                    {
                        i++;
                        form.Invoke(SetTextAction, new Object[1] { i.ToString() });
                    } 
                } while (!isStop);
            }
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (isStop)
            {
                isStop = false;
                thread = new Thread(SThread.SubThreadStartFunction);
                thread.Start();
            }
            isPause = false;
        }

        private void buttonPause_Click(object sender, EventArgs e)
        {
            isPause = true;
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            isStop=true;
        }
    }
}

“form.Invoke(SetTextAction, new Object[1] { i.ToString() });”这一句不知道是做什么用的呀?如果我的SetTextAction有两个参数,应该怎么写呢?


if (!isPause){}中的语句就是你要在后台执行的语句。
如果这里的语句不涉及对窗口线程的操作(对窗口、控件和属性的操作),那么你可以直接在里面写。
如果你想在附属线程操作窗口在组件(比如反馈进度,我这里更改窗口标题来显示循环的进度),则涉及跨线程访问窗口控件。我这里使用form.Invoke,实现在form的线程调用一个函数。在这个函数里操作窗口控件。
Invoke方法有两个参数。一个是要在窗口线程中操作的函数的委托(相当于函数的指代),另一个是数组,是这个函数的参数。
如果你有两个参数,需要Invoke(xxx,new Object[2]{参数1,参数2})
相应的,函数委托变量的声明也要改成 Action <参数1的类型,参数2的类型> xxx
具体的执行函数,也要改成两个参数的。

在新线程里,绝大部分操作都应该不是直接针对窗口和控件的,否则这个线程就没有意义。
但如果要报告进度,也许需要不定期的调用,这才会用到窗口的Invoke方法。

对于你留言提到的:
您好,您回复我的帖子http://bbs.csdn.net/topics/390671805?page=1#post-396363023。当我把SetText()的定义改为以下几句,为什么点击“开始”之后,就再也不能点其他按钮呢? this.Text = Convert.ToString(1); Thread.Sleep(5000); 这两句

你不要在Invoke方法调用的委托所指代的函数中执行 Thread.Sleep(5000)。这相当于把窗口线程卡死了。(form.Invoke方法所在的 form的线程(主线程) 被委托SetTextAction 所指代的 SetText函数中的sleep语句给挂起了)
你可能需要这么改
if (!isPause)
{
    i++;
    form.Invoke(SetTextAction, new Object[1] { i.ToString() });
    Thread.Sleep(5000); 

这才是在新的线程中休眠,并定期通过Invoke方法访问窗口的标题属性报告进度。

您好,您给我的程序是用循环来制造连续执行的子线程。但是我想在子线程中执行的是一句句的语句(中间穿插Thread()来实现暂停)。那样我的这些语句应该放到哪里呢?这些语句我已经写好。如下:
if (azimuth != 0.0)
            {
                azmMotPositionStart(azimuth);   //运动到平面位置
            }
            zenithObservation(azimuth);    //平面观测
            float azimuthInterval = Convert.ToInt32(txtBoxAzmInterval.Text);

            for (float azimuthRealPosition = azimuth; azimuthRealPosition <= 180 + azimuth; azimuthRealPosition += azimuthInterval)  //180°内进行方位观测
            {
                azmMotPositionStart(azimuthInterval);    //运动到下一方位平面位置
                Thread.Sleep(40000);   
                zenithObservation(azimuthRealPosition);  //在该平面进行数据采集
                Thread.Sleep(36000);   
            }
实在不懂了。求助大侠! --------------------编程问答-------------------- 除 --------------------编程问答--------------------
引用 8 楼 sdqdpdldyq 的回复:
Quote: 引用 7 楼 u012592437 的回复:

Quote: 引用 6 楼 sdqdpdldyq 的回复:

Quote: 引用 2 楼 u012592437 的回复:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            SThread.SetTextAction = SetText;
            SThread.form = this;
            isPause = true;
            isStop = true;
        }
        private static Boolean isPause = true;
        private static Boolean isStop = false;
        private SubThread SThread = new SubThread();
        private Thread thread;
        public void SetText(String text)
        {
            this.Text = text;
        }
        public class SubThread
        {
            public Form form;
            public Action<String> SetTextAction;
            public void SubThreadStartFunction()
            {
                int i=0;
                do
                {
                    if (!isPause)
                    {
                        i++;
                        form.Invoke(SetTextAction, new Object[1] { i.ToString() });
                    } 
                } while (!isStop);
            }
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (isStop)
            {
                isStop = false;
                thread = new Thread(SThread.SubThreadStartFunction);
                thread.Start();
            }
            isPause = false;
        }

        private void buttonPause_Click(object sender, EventArgs e)
        {
            isPause = true;
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            isStop=true;
        }
    }
}

“form.Invoke(SetTextAction, new Object[1] { i.ToString() });”这一句不知道是做什么用的呀?如果我的SetTextAction有两个参数,应该怎么写呢?


if (!isPause){}中的语句就是你要在后台执行的语句。
如果这里的语句不涉及对窗口线程的操作(对窗口、控件和属性的操作),那么你可以直接在里面写。
如果你想在附属线程操作窗口在组件(比如反馈进度,我这里更改窗口标题来显示循环的进度),则涉及跨线程访问窗口控件。我这里使用form.Invoke,实现在form的线程调用一个函数。在这个函数里操作窗口控件。
Invoke方法有两个参数。一个是要在窗口线程中操作的函数的委托(相当于函数的指代),另一个是数组,是这个函数的参数。
如果你有两个参数,需要Invoke(xxx,new Object[2]{参数1,参数2})
相应的,函数委托变量的声明也要改成 Action <参数1的类型,参数2的类型> xxx
具体的执行函数,也要改成两个参数的。

在新线程里,绝大部分操作都应该不是直接针对窗口和控件的,否则这个线程就没有意义。
但如果要报告进度,也许需要不定期的调用,这才会用到窗口的Invoke方法。

对于你留言提到的:
您好,您回复我的帖子http://bbs.csdn.net/topics/390671805?page=1#post-396363023。当我把SetText()的定义改为以下几句,为什么点击“开始”之后,就再也不能点其他按钮呢? this.Text = Convert.ToString(1); Thread.Sleep(5000); 这两句

你不要在Invoke方法调用的委托所指代的函数中执行 Thread.Sleep(5000)。这相当于把窗口线程卡死了。(form.Invoke方法所在的 form的线程(主线程) 被委托SetTextAction 所指代的 SetText函数中的sleep语句给挂起了)
你可能需要这么改
if (!isPause)
{
    i++;
    form.Invoke(SetTextAction, new Object[1] { i.ToString() });
    Thread.Sleep(5000); 

这才是在新的线程中休眠,并定期通过Invoke方法访问窗口的标题属性报告进度。

您好,您给我的程序是用循环来制造连续执行的子线程。但是我想在子线程中执行的是一句句的语句(中间穿插Thread()来实现暂停)。那样我的这些语句应该放到哪里呢?这些语句我已经写好。如下:
if (azimuth != 0.0)
            {
                azmMotPositionStart(azimuth);   //运动到平面位置
            }
            zenithObservation(azimuth);    //平面观测
            float azimuthInterval = Convert.ToInt32(txtBoxAzmInterval.Text);

            for (float azimuthRealPosition = azimuth; azimuthRealPosition <= 180 + azimuth; azimuthRealPosition += azimuthInterval)  //180°内进行方位观测
            {
                azmMotPositionStart(azimuthInterval);    //运动到下一方位平面位置
                Thread.Sleep(40000);   
                zenithObservation(azimuthRealPosition);  //在该平面进行数据采集
                Thread.Sleep(36000);   
            }
实在不懂了。求助大侠!


把你这段代码直接放进SubThreadStartFunction()。
这段代码要想快速响应暂停和停止,需要把Sleep之类的耗时语句切碎。
(不可进一步切碎的耗时的操作将会成为控制线程暂停响应速度的瓶颈。)
例如:
Thread.Sleep(40000);   变成

for(i=0;i<100;i++)
{
    Thread.Sleep(400);
    if (isStop)
    {
        return;
    }
    do
    {
    } while (isPause);//如果标记为暂停,就进入死循环等待。
}
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,