【问题标题】:Stop SoundPlayer on mouseUp event在 mouseUp 事件上停止 SoundPlayer
【发布时间】:2015-01-04 08:52:10
【问题描述】:

tl;dr 版本:如何在 WinForms 按钮的 MouseDown 事件中开始播放声音,并在同一个按钮的 MouseUp 事件中停止播放?

这里是中级 C# 开发人员,我一直在尝试编写一个简单的 Simon 克隆。

我目前正试图让它仅在用户单击按钮时播放彩色按钮的声音。 (我交替使用“按钮”和“平铺”。两者都指用户将在表单上按下的彩色按钮)

我最初尝试过这个:

public partial class frmMain : Form
{
    private SoundPlayer soundPlayer;

    private void btnGreenTile_MouseDown(object sender, MouseEventArgs e)
    {
        soundPlayer = new SoundPlayer(Properties.Resources.greenTileSound)
        soundPlayer.Play();
    }

    private void btnGreenTile_MouseUp(object sender, MouseEventArgs e)
    {
        soundPlayer.Stop();
    }
}

但这并没有停止声音,因为 MouseUp 事件没有触发,因为 MouseDown 没有完成(仍然播放大约 5 秒长的声音,以防有人按住按钮的时间超过一个简单的点击)。正如 Luis Tellez 在 cmets 中提到的,SoundPlayer 会在新线程上播放声音......所以我不知道为什么这段代码现在不起作用。

所以我研究了多线程并尝试了这个:

public partial class frmMain : Form
{
    private Thread soundThread = new Thread(new ParameterizedThreadStart(PlaySound));

    // Create stream objects for each sound (needed to allow SoundPlayer to use Resources)
    private Stream greenTileSound = Properties.Resources.greenTilePress;
    private Stream redTileSound = Properties.Resources.redTilePress;
    private Stream yellowTileSound = Properties.Resources.yellowTilePress;
    private Stream blueTileSound = Properties.Resources.blueTilePress;

    public frmMain()
    {
        InitializeComponent();
    }

    private void btnGreenTile_MouseDown(object sender, MouseEventArgs e)
    {
        soundThread.Start(greenTileSound); 
    }

    private void btnGreenTile_MouseUp(object sender, MouseEventArgs e)
    {
        soundThread.Abort();
    }

    // Have to use object as parameter because ParamterizedThreadStart() only takes object arguments
    private static void PlaySound(object soundToPlay)
    {
        SoundPlayer soundPlayer = new SoundPlayer((Stream)soundToPlay);
        soundPlayer.Play();
    }
} 

使用上面的代码,它不会停止在 MouseUp 上播放声音,甚至更好的是它会抛出 ThreadStateException 并显示消息“线程正在运行或终止;它无法重新启动”。

正如您可能知道的那样,我只是在尝试编写此代码时才了解多线程。我必须使用 ParameterizedThreadStart,因为它在线程启动时调用的方法 PlaySound() 需要将参数传递给 soundPlayer,其资源对应于播放器按下的彩色按钮(.wav 文件)。

然后我想也许我应该尝试使用 soundThread.Suspend() 而不是 soundThread.Abort() 但 Suspend 已被弃用...

谁能指出我正确的方向以使声音在 MouseUp 上停止?我需要使用多线程吗?我认为我的问题归结为逻辑,但我完全陷入困境。 感谢您的所有帮助! :)

作为旁注,我有点惊讶这个问题或类似的问题还没有被问到(至少我在 google 搜索或 stackExchange 搜索中找不到它)。

【问题讨论】:

  • 我试图重新创建您的问题(首先,非线程方法),但是通过将 SoundPlayer 指向确切的文件位置而不是使用流来做到这一点,它工作得很好,所以试着看看了解流的工作原理,问题可能就在那里。
  • 从头开始,它甚至适用于流。 Properties.Resources.greenTilePress 背后的代码是什么?
  • Properties.Resources.greenTilePress 是一个资源(.wav 文件)我添加了 Visual Studio 项目,因此它将包含在 exe 中。在您发表评论后,我再次尝试了非线程方法并且它起作用了(我从这里复制并粘贴了代码)。我不知道为什么它以前不起作用。感谢您的帮助!

标签: c# multithreading 2d-games soundplayer


【解决方案1】:

您可以在文档中看到 play() 方法在其他线程中运行,您可以在它之后执行其他操作并且它应该运行,因此第一种方法的问题与您的想法不同。

Play 方法使用新线程播放声音。如果你打电话给 Play 在 .wav 文件加载到内存之前,.wav 文件将 在播放开始之前加载。您可以使用 LoadAsync 或 Load 方法将 .wav 文件提前加载到内存中。在 .wav 文件之后 从 Stream 或 URL 成功加载,以后调用播放 SoundPlayer 的方法不需要重新加载 .wav 文件 直到声音的路径改变。如果 .wav 文件尚未 指定或加载失败,Play 方法将播放默认值 哔声。

http://msdn.microsoft.com/en-us/library/system.media.soundplayer.play%28v=vs.110%29.aspx

【讨论】:

  • 我在你发布的代码中看不到任何原因,据我了解它应该可以工作,如果你在 GIT 上有这个,我可以克隆它并测试它。
  • 是的,第一个代码确实有效。我不知道为什么它以前对我不起作用,但显然我搞砸了。非常感谢您的时间和帮助!
猜你喜欢
  • 1970-01-01
  • 2016-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多