-1

我有一个小的 Windows 窗体程序,它使用来自字符串的 console.beep 播放音乐。我在一个新线程“t”中设置了字符串播放位(基本上是一个 for 循环,逐个字符地遍历字符串并播放适当的音符)。当您点击“播放”按钮时,线程启动并且按钮变为“停止”按钮。如果你现在在播放音乐时点击这个“停止”按钮,它将停止并且按钮变回播放(通过调用“完成”方法。我的问题是我希望在新线程中运行的循环也调用当循环已经运行并且歌曲结束时的“完成”方法。但是如果我在循环之后放置完成(),我会得到“非静态字段需要对象引用”错误。如果我更改“完成”

这是您按下按钮时的代码...

//This is the method for when the "start" button is clicked
public void button1_Click(object sender, EventArgs e) 
    {
        if (music == null) { return; }

        if (button1.Text == "Play")
        {
            // it makes a new thread which calls my "parse" method which 
            // interprets the music and then calls "playnote" to play it.
            Thread t = new Thread(parse); 
            t.Start();
            button1.Text = "Stop";
        }
        else 
        {
            finished();
        }
    }

    public void finished()
    {
        stop = true;
        button1.Text = "Play";
    }

有什么建议么?

提前非常感谢!

编辑:谢谢大家!!我真的没有时间弄清楚后台工作人员 atm 所以我现在只有单独的开始和停止按钮!:p

4

7 回答 7

4

我认为使用 BackgroundWorker 线程会更好地完成。这样您就可以在事件中调用该finished()方法。RunWorkerCompleted

于 2012-06-14T18:31:56.127 回答
1

parse() 方法是静态的吗?似乎您试图在不提供实例的情况下从静态方法调用 finished(),这就是为什么您会收到“非静态字段需要对象引用”错误的原因。

于 2012-06-14T18:31:54.223 回答
0

您需要做的是确保创建的线程可以访问创建它的对象(即“this”,在“button1_Click()”方法的范围内)。为此,您可以调用 t.Start(this) 而不是 t.Start()。这样做时,您将向线程传递能够调用“finished()”方法的对象。接下来,您需要确保“parse”方法采用 Object 类型的参数。这样做时,当您调用“t.Start(this)”时,“parse”方法将接收“this”作为参数。需要进行简单的强制转换才能转换为适当的类型。现在,当您希望歌曲在线程中停止时,只需在 cast 参数上调用“finish()”方法即可。所以你的代码应该是这样的:

public void parse(object o) { MyClass c = o as MyClass; // 用你的类名替换 MyClass

[...] // play music here

c.finished();  // call finished when you are done

}

public void button1_Click(object sender, EventArgs e) { [...]

线程 t = 新线程(解析);t.开始(这个);// 而不是 t.Start()

[...] }

于 2012-06-14T18:38:19.520 回答
0

静态与成员方法

  1. 要么你有一个成员(非静态)方法,你调用它
obj.SomeMethod();
  1. 或者你有一个静态方法,你用
ClassName.SomeMethod();

除非在定义类本身内部调用它。然后可以简单地调用它

SomeMethod();

在这两种情况下。


穿线

唯一允许与 UI 交互的线程(例如 with button1.Text)是 UI 线程本身。UI 线程是代码正常运行的主线程。

请参阅如何从 C# 中的另一个线程更新 GUI?用于与来自另一个线程的表单进行交互。

于 2012-06-14T18:42:12.720 回答
0

你需要做的是在主线程上引发一个事件来调用你完成的方法。首先在表单类中声明事件和委托。

public delegate void CallFinishedEventHandler();
public event CallFinishedEventHandler CallFinished;

然后创建一个事件处理程序,该处理程序将在引发事件时调用,并在调用完成的方法时调用。

void Form1_CallFinished()
{
  Finished();
}

然后在您的表单构造函数中将您的事件处理程序连接到您的事件。

public Form1()
{
    CallFinished += Form1_CallFinished;
}

最后,在您的音乐播放代码中,当您想要调用完成的方法(在 UI 线程上)时,调用您的事件,以便在 UI 线程上触发它。

this.Invoke(CallFinished);
于 2012-06-14T18:51:36.480 回答
0

这很简单,创建一个全局线程,然后在你想要的地方访问它。

Thread t;
    public void button1_Click(object sender, EventArgs e) 
        {
            if (music == null) { return; }

            if (button1.Text == "Play")
            {
                // it makes a new thread which calls my "parse" method which 
                // interprets the music and then calls "playnote" to play it.
                t = new Thread(parse); 
                t.Start();
                button1.Text = "Stop";
            }
            else 
            {
                finished();
            }
        }

        public void finished()
        {
            stop = true;
            button1.Text = "Play";
        }
于 2013-09-21T23:15:46.747 回答
-3

要调用完成,请创建表单类的实例,然后调用该方法。

Form1 frm1 = new Form1();
frm1.finished();
于 2012-06-14T18:33:19.530 回答