none
在循环中,如何加入“按Esc键中止”功能? RRS feed

  • 问题

  • 窗体中有一ContextMenuStrip,其中某个ToolStripMenuItem.Click事件中,执行类似如下代码:

    For each ...

    '提示用户:正在......按Esc键中止

    '执行代码

    Next

    也就是说,在执行过程中,用户可随时按Esc键中止。

    但是,点击菜单项后,它失去焦点,无法捕捉KeyDown事件,是不是要在窗体的KeyDown事件中处理呢?如何实现这一功能比较好呢?


    韩立学


    2013年6月13日 1:52

答案

  • 尝试把Form的KeyPriview设置为true(窗体捕获按键)。

    另外执行一个长时间的任务可能导致卡死,建议这样做功能:

    Imports System.Threading.Tasks
    Imports System.Threading
     
    Public Class Form1
        '取消标识符
        Private sourceCancel As New CancellationTokenSource
        Private flag As CancellationToken = sourceCancel.Token
     
     
        Private Sub LoopingToolStripMenuItem_Click(sender As Objecte As EventArgsHandles LoopingToolStripMenuItem.Click
            Dim task As New Task(Sub()
                                     For index = 1 To 100
                                         If (flag.IsCancellationRequestedThen
                                             MsgBox("正在取消……")
                                             flag.ThrowIfCancellationRequested()
                                         End If
                                         '模拟大数据量缓慢处理的进程,如果需要和UI交互,请直接使用BeginInvoke方法处理
                                         Threading.Thread.Sleep(1000)
                                     Next
                                 End Subflag)
            task.Start()
        End Sub
     
        Private Sub Form1_KeyDown(sender As Objecte As KeyEventArgsHandles MyBase.KeyDown
            If (e.KeyCode = Keys.EscapeThen
                '取消
                sourceCancel.Cancel()
            End If
        End Sub
    End Class

    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats


    Found any spamming-senders? Please report at: Spam Report

    2013年6月13日 2:07
    版主
  • 另外参考使用BackGroundWorker:

    代码

    尝试把Form的KeyPriview设置为true(窗体捕获按键)。

    Imports System.Threading.Tasks
    Imports System.Threading
    Imports System.ComponentModel
     
    Public Class Form1
        '是否取消标识符
        Private flag As Boolean = False
     
        Private Sub DoHeavyWork(sender As Objecte As System.ComponentModel.DoWorkEventArgs)
            Dim bgWork As BackgroundWorker = CType(senderBackgroundWorker)
     
            For i As Integer = 1 To 100
                If (flagThen
                    '取消
                    e.Cancel = True
                    Exit For
                End If
                Thread.Sleep(1000)
                bgWork.ReportProgress(i)
            Next
        End Sub
     
        Private Sub LoopingToolStripMenuItem_Click(sender As Objecte As EventArgsHandles LoopingToolStripMenuItem.Click
            bgBusy.RunWorkerAsync()
        End Sub
     
        Private Sub Form1_KeyDown(sender As Objecte As KeyEventArgsHandles MyBase.KeyDown
            '取消
            flag = True
        End Sub
     
        Private Sub Form1_Load(sender As Objecte As EventArgsHandles MyBase.Load
     
        End Sub
     
        Private Sub bgBusy_DoWork(sender As Objecte As System.ComponentModel.DoWorkEventArgsHandles bgBusy.DoWork
            DoHeavyWork(sendere)
        End Sub
     
        Private Sub bgBusy_ProgressChanged(sender As Objecte As ProgressChangedEventArgsHandles bgBusy.ProgressChanged
            ProgressBar1.Value = e.ProgressPercentage
        End Sub
     
        Private Sub bgBusy_RunWorkerCompleted(sender As Objecte As RunWorkerCompletedEventArgsHandles bgBusy.RunWorkerCompleted
            If (e.CancelledThen
                MsgBox("Cancelled")
            Else
                MsgBox("Finished")
            End If
        End Sub
    End Class

    运行效果:


    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats


    Found any spamming-senders? Please report at: Spam Report

    2013年6月13日 2:19
    版主

全部回复

  • 尝试把Form的KeyPriview设置为true(窗体捕获按键)。

    另外执行一个长时间的任务可能导致卡死,建议这样做功能:

    Imports System.Threading.Tasks
    Imports System.Threading
     
    Public Class Form1
        '取消标识符
        Private sourceCancel As New CancellationTokenSource
        Private flag As CancellationToken = sourceCancel.Token
     
     
        Private Sub LoopingToolStripMenuItem_Click(sender As Objecte As EventArgsHandles LoopingToolStripMenuItem.Click
            Dim task As New Task(Sub()
                                     For index = 1 To 100
                                         If (flag.IsCancellationRequestedThen
                                             MsgBox("正在取消……")
                                             flag.ThrowIfCancellationRequested()
                                         End If
                                         '模拟大数据量缓慢处理的进程,如果需要和UI交互,请直接使用BeginInvoke方法处理
                                         Threading.Thread.Sleep(1000)
                                     Next
                                 End Subflag)
            task.Start()
        End Sub
     
        Private Sub Form1_KeyDown(sender As Objecte As KeyEventArgsHandles MyBase.KeyDown
            If (e.KeyCode = Keys.EscapeThen
                '取消
                sourceCancel.Cancel()
            End If
        End Sub
    End Class

    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats


    Found any spamming-senders? Please report at: Spam Report

    2013年6月13日 2:07
    版主
  • 另外参考使用BackGroundWorker:

    代码

    尝试把Form的KeyPriview设置为true(窗体捕获按键)。

    Imports System.Threading.Tasks
    Imports System.Threading
    Imports System.ComponentModel
     
    Public Class Form1
        '是否取消标识符
        Private flag As Boolean = False
     
        Private Sub DoHeavyWork(sender As Objecte As System.ComponentModel.DoWorkEventArgs)
            Dim bgWork As BackgroundWorker = CType(senderBackgroundWorker)
     
            For i As Integer = 1 To 100
                If (flagThen
                    '取消
                    e.Cancel = True
                    Exit For
                End If
                Thread.Sleep(1000)
                bgWork.ReportProgress(i)
            Next
        End Sub
     
        Private Sub LoopingToolStripMenuItem_Click(sender As Objecte As EventArgsHandles LoopingToolStripMenuItem.Click
            bgBusy.RunWorkerAsync()
        End Sub
     
        Private Sub Form1_KeyDown(sender As Objecte As KeyEventArgsHandles MyBase.KeyDown
            '取消
            flag = True
        End Sub
     
        Private Sub Form1_Load(sender As Objecte As EventArgsHandles MyBase.Load
     
        End Sub
     
        Private Sub bgBusy_DoWork(sender As Objecte As System.ComponentModel.DoWorkEventArgsHandles bgBusy.DoWork
            DoHeavyWork(sendere)
        End Sub
     
        Private Sub bgBusy_ProgressChanged(sender As Objecte As ProgressChangedEventArgsHandles bgBusy.ProgressChanged
            ProgressBar1.Value = e.ProgressPercentage
        End Sub
     
        Private Sub bgBusy_RunWorkerCompleted(sender As Objecte As RunWorkerCompletedEventArgsHandles bgBusy.RunWorkerCompleted
            If (e.CancelledThen
                MsgBox("Cancelled")
            Else
                MsgBox("Finished")
            End If
        End Sub
    End Class

    运行效果:


    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats


    Found any spamming-senders? Please report at: Spam Report

    2013年6月13日 2:19
    版主
  • 注意第二个示例代码中不要忘记设置以上属性!

    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats


    Found any spamming-senders? Please report at: Spam Report

    2013年6月13日 2:25
    版主
  • 谢谢回复!

    我用的是VS2010,单线程有无更好的办法?


    韩立学

    2013年6月13日 2:31
  • 谢谢回复!

    我用的是VS2010,单线程有无更好的办法?


    韩立学


    参考我的第二个回复(BackGroundWorker)

    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats


    Found any spamming-senders? Please report at: Spam Report

    2013年6月13日 2:31
    版主
  • 谢谢回复!

    我用的是VS2010,单线程有无更好的办法?


    韩立学


    其实VS2010照样可以使用这个功能,选择net framework4即可。

    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats


    Found any spamming-senders? Please report at: Spam Report

    2013年6月13日 2:34
    版主