打个比方:2个按钮运行
第一个按钮点了运行到一半,点了第二个按钮,程序会运行第二个按钮的事件
直到第二个按钮的事件运行结束,再把第一个按钮的事件运行完,想解决上边的问题有没有什么好的办法:
触发了第二个按钮的事件后能不能判断下有没别的没运行完,有的话让它先运行完

解决方案 »

  1.   


    不会吧?除非你在第一个事件代码中插入 DoEvents 等着第二个事件。即便如此,也可以采用“令牌”方式。例如,用一个全局变量 Public Running As Boolean。每个事件代码中都加上:Private Sub xxxx(...)If Running Then Exit SubRunning = True...... '原来的事件代码Running = FalseEnd Sub此外,还可以禁止按钮:Private Sub Command1_Click()
    Command1.Enabled = False
    Command2.Enabled = False...... '原来的事件代码Command1.Enabled = True
    Command2.Enabled = True
    End Sub
      

  2.   

    Private Sub btnRoll_Click(Index As Integer)
        Call Roll(Index)
    End Sub
    Private Sub Roll(ByVal Index As Integer)
        Dim i As Long
        For i = 1 To 100000
            Label1(Index).Caption = i
            DoEvents
        Next
    End Sub这是测试,两个数组按钮btnRoll,2个标签Label1
      

  3.   


    1 To 100000
    太长了
    改成 1 To 10000点 第一个(第一次),马上又点第二个 ,接着又点第一个(第二次)Label1 转了一部分 停下了 ,Label2 开始转 ,又停下了,然后 Label1 从1 开始直到结束
    Label2 开始接着转直到结束,Label1 从第一次停下的地方开始转直到结束。
    这是正常效果,这两个按钮,不管你连续点了多少次,Roll就执行多少次,
    最后点的先执行完,最开始点的压在栈中 ,最后执行完。楼主想要实现什么样的效果?
      

  4.   

    你加了doevents么,当然就会中间去响应其他按钮事件咯.解决的方法很简单, 只要在第一按钮事件开始的时候把其他按钮的enabled都设为false直到第一个按钮事件中的程序运行结束,再把其他按钮的Enabled设回true
      

  5.   

    将doevents去掉,让函数专心干自己的活,别左顾右盼的。
    不过会有个后遗症,就是主线程卡死~~~
      

  6.   

    最简单有效的方法就是 timer 控件了Dim runing As Boolean, inx As Integer
    Private Sub btnRoll_Click(Index As Integer)
       btnRoll(Index).Enabled = False
       inx = Index
       Timer1.Enabled = True    
    End Sub
    Private Sub Roll(ByVal Index As Integer)
        runing = True
        Dim i As Long
        For i = 1 To 10000
            Label1(Index).Caption = i
            DoEvents
        Next
        runing = False
        btnRoll(Index).Enabled = True
    End SubPrivate Sub Form_Load()
        Timer1.Enabled = False
        Timer1.Interval = 10
    End SubPrivate Sub Timer1_Timer()
        If runing Then Exit Sub
        Timer1.Enabled = False
        Call Roll(inx)
    End Sub
      

  7.   

    这个函数只是例子,实际函数很复杂,有外部控件还有api,
    即使不加doevents也会被中断
      

  8.   

    我不认为你真的会,只是timer退出而已,第一个运行完第二个自然就会运行,况且20分有人接茬,你就偷着乐吧。
      

  9.   

    呵呵,我只是说明需要实现的效果,
    分不够可以加,300分也可以用enable或者直接退出当前工程的,这不是我要的效果,解决不了现在的问题
      

  10.   

    多线程里边有个WaitForSingleObject等待同步的api,
    我在vb里老是用不起来,不知道哪位大虾能用到上边5楼的例子中去就好了
      

  11.   

    对于VB而言,它不是多线程的,所以你点击了Command1,系统执行Command1_CLick,在这期间,你点击Command2,系统是不会停止执行Command1_Click,转而执行Command2_Click的,必须等待Command1_Click执行完毕了,再执行Command2_Click。这就是单线程。
    不过如果你的Command1_Click中含有DoEvents语句,那么系统就会使Command1_Click让出CPU时间,来响应其它的事件,所以:Command2_Click事件就有可能被执行了。要实现楼主的想法,最好是用多线程,不过,VB6.0不能良好的支持多线程,并不可行。所以在Command1_Click的合适位置加入DoEvents是一个可行的办法。
      

  12.   

    可怜的vb多线程,vb肯定有几个运行点,既然这个函数被中断了,下一个函数运行完还会回到这个点运行,
    能不能读到这个点,让他运行,或者把下一个函数的优先级调到最低(如果当前有别的过程正在执行,那么等待那个函数执行完,并且把运行点还给它)
      

  13.   

    操作系统中的优先级概念是针对操作系统为基准的,它有它的管理机制,对于VB进程而言,操作系统是不能细化它的,除非该进程是多线程的。所以,你所谓的优先级问题,不适合与你所说的这个场合。所谓优先级是运用程序向操作系统申请CPU资源,由操作系统来判断分配,优先级高的优先分配,优先级低的靠后分配。试问!如果你的VB进程连这个请求都没有给操作系统发送,那么怎么来中断正在执行的过程?
      

  14.   

    Dim runing As Boolean
    Private Sub btnRoll_Click(Index As Integer)
     if runing then 
         '等待 并 让前面的Roll继续运行
         do while runing
           DoEvents
          '看起来很美 但一定不管用 ,如果不用多线程,还是只有用 timer
          '不用timer,也许这个对你有用  
           'http://www.vbgood.com/viewthread.php?tid=93124&extra=&page=1
         loop
      end if
       Roll Index
    End Sub
    Private Sub Roll(ByVal Index As Integer)
        runing = True
        Dim i As Long
        For i = 1 To 10000
            Label1(Index).Caption = i
            DoEvents
        Next
        runing = False   
    End Sub
      

  15.   

    这样我也早就做过了,还是没有明白我上边说的过程
    1运行后,运行2,1被中断,
    你上边的效果是2不停的循环判断那个全局变量值,
    但是1被中断了,并没有任何运行,1也不会运行到结束,去改变全局变量runing = False最后就是2的循环永远不退出,而1还在等待2运行完再继续运行
      

  16.   

    听楼主提到WaitForSingleObject函数,我倒是有一个想法,可以尝试创建一个event,每次按下按钮的时候首先判断event的状态,如果是开的话就关闭,然后运行自己,运行完毕之后再打开。否则就WaitForSingleObject 这个event。不过这样的话第二次按下按钮的时候主线程一定会卡死,因为调用了WaitForSingleObject
    于是程序会变成这样:按第一下,程序开始跑,按第二次的时候主线程卡死了,整个程序处于无响应状态。然后等第一个跑完了,第二个才开始跑,程序界面恢复响应。这时候按第三次,主线程又卡死了。
      

  17.   

    .....其实你这个引入队列机制就挺好.请求进入--------->添加到队列------->等待当前请求被处理后返回然后处理模块不断地从队列里取请求来处理.
      

  18.   

    嗯···确实是这样的,原因在于doevents和消息循环,两个共同作用的效果这个问题应该这样试试,在command2_click的开始处,写 doevents其实这个问题,和这个执行效果90%的人都不理解,甚至抵制,是没办法的事情单线程虽然是以顺序方式执行的,但消息循环(消息队列)和可以吃掉当前消息的doevents,使得调用被暂停了消息循环中新的消息被发送到执行过程,这样新的代码过程执行了,直到他执行完,被暂停的过程才会继续直到完成可以视为单线程异步。只不过他和真正的异步是存在很大区别的
      

  19.   

    问题就出在等待返回的上边,除非去创建线程,
    这是的很大的工程,不敢,也不想去用那个,
    其实可以把这个函数写到别的exe里边用等待进程结束或许可以达到效果,
    但是最好也不想这么做软件结构也不太可能改
      

  20.   

     前一个解释错误,从新发这个问题还要从doevents的实现说起,我也是刚刚想透的,这个问题我也困扰了很久了doevents 的实现getmessage 0,0,0,0
     peekmessage 0,0,0,0,pm_remove
     TranslateMessage
     DispatchMessage
     sleep 0doevents之所以能释放cpu资源,在于 sleep 0,之所以能改变流程在于 DispatchMessage,DispatchMessage接受来自getmessage取自消息队列的消息,然后发往相应的窗口执行,于是乎我一直觉得这个应该是靠着栈堆实现的所谓的异步应该是getmessage作用,刚才灵光闪现,终于想通了
      

  21.   

    TranslateMessage
     DispatchMessage
    这些vb怎么用
      

  22.   

    如果doevents是这个逻辑的话,就麻烦了,
    不可能递归的消息先执行外层消息;
    晕死,这样完全混乱
      

  23.   

    赶快用vb.net编程吧,多线程还是容易做.挖哈哈哈!据说在VB里用多线程也不太稳定.
      

  24.   

    使用函数指针加异常处理可以完成你的要求使用函数指针把nop函数变成int 3然后触发异常再那六可以随便更改eip那样不就简单了
      

  25.   

    试试这个:-)
    Option ExplicitPrivate mblnRunning As Boolean
    Private mlngCount As LongPrivate Sub DoTask()
        Dim i As Long
        For i = 0 To 1000000
            DoEvents
        Next
        Debug.Print "Done"
    End SubPrivate Sub Command1_Click()
        If mblnRunning Then
            mlngCount = mlngCount + 1
            Exit Sub
        End If
        
        Do
            Call DoTask
            mlngCount = mlngCount - 1
        Loop While mlngCount > 0
    End Sub
      

  26.   

    刚才的有点问题,试试这个:>Option ExplicitPrivate mblnRunning As Boolean
    Private mlngCount As LongPrivate Sub DoTask()
        Dim i As Long
        For i = 0 To 1000000
            DoEvents
        Next
        Static c As Long
        c = c + 1
        Debug.Print c & " Done"
    End SubPrivate Sub Command1_Click()
        Static c As Long
        c = c + 1
        Debug.Print c & " Clicked!"
        
        If mblnRunning Then
            mlngCount = mlngCount + 1
            Exit Sub
        End If
        
        mlngCount = mlngCount + 1
        mblnRunning = True
        Do
            Call DoTask
            mlngCount = mlngCount - 1
        Loop While mlngCount > 0
        
        mblnRunning = False
    End Sub
      

  27.   

    这个如何?
    Option ExplicitPrivate mlngtaskid As LongPrivate Sub Command1_Click()
        mlngtaskid = mlngtaskid + 1
        
        Dim lngTaskID As Long
        lngTaskID = mlngtaskid
        Debug.Print lngTaskID & " Clicked!"
        
        Dim i As Long
        For i = 0 To 1000000
            Do
                DoEvents
            Loop While lngTaskID <> mlngtaskid
        Next    mlngtaskid = mlngtaskid - 1
        Debug.Print lngTaskID & " Done!"
    End Sub
      

  28.   

    1 Clicked!
    2 Clicked!
    2 Done!
    1 Done!
      

  29.   

    不是1 Clicked!
    2 Clicked!
    1 Done!
    2 Done!
      

  30.   

    39楼事件错乱了
    debug显示内容不对,应该改一下
    Option ExplicitPrivate mblnRunning As Boolean
    Private mlngCount As LongPrivate Sub DoTask(ByVal d As Long)
        Dim i As Long
        For i = 0 To 1000000
            DoEvents
        Next
        Debug.Print d & " Done"
    End SubPrivate Sub Command1_Click()
        Static c As Long
        c = c + 1
        Debug.Print c & " Clicked!"
        
        If mblnRunning Then
            mlngCount = mlngCount + 1
            Exit Sub
        End If
        
        mlngCount = mlngCount + 1
        mblnRunning = True
        Do
            Call DoTask(c)
            mlngCount = mlngCount - 1
        Loop While mlngCount > 0
        
        mblnRunning = False
    End Sub结果
    1 Clicked!
    2 Clicked!
    3 Clicked!
    1 Done
    3 Done
    3 Done
      

  31.   

    其实是没有错乱的,DoTask是一个一个的在循环中运行的,c传递进去并不代表什么.
    等我改一下你就看出来了...
      

  32.   

    Form1.frm代码
    Option ExplicitPrivate mblnRunning As Boolean
    Private mCol As New CollectionPrivate Function GenID() As Long
        Static id As Long
        id = id + 1
        
        GenID = id
    End Function
    Private Sub Command1_Click()
        Static c As Long
        c = c + 1
        Debug.Print c & " Clicked!"
        
        Dim ti As TaskInfo
        Set ti = New TaskInfo
        Call ti.SetUp(GenID())
        Call mCol.Add(ti)
        
        If mblnRunning Then
            Exit Sub
        End If
        
        mblnRunning = True
        
        Do
            Call mCol.Item(1).DoTask
            Call mCol.Remove(1)
        Loop While mCol.Count > 0
        
        mblnRunning = False
    End SubTaskInfo.cls代码
    Option ExplicitPrivate mlngID As LongPublic Sub SetUp(ByRef id As Long)
        mlngID = id
    End Sub
    Public Sub DoTask()
        Dim i As Long
        For i = 0 To 1000000
            DoEvents
        Next
        
        Debug.Print mlngID & " Done!"
    End Sub
      

  33.   

    Option ExplicitPrivate mblnRunning As Boolean
    Private mCol As New CollectionPrivate Sub Command1_Click()
        Static c As Long
        c = c + 1
        Debug.Print c & " Clicked!"
        
        Dim ti As TaskInfo
        Set ti = New TaskInfo
        Call ti.SetUp(c)
        Call mCol.Add(ti)
        
        If mblnRunning Then
            Exit Sub
        End If
        
        mblnRunning = True
        
        Do
            Call mCol.Item(1).DoTask
            Call mCol.Remove(1)
        Loop While mCol.Count > 0
        
        mblnRunning = False
    End Sub这样也行:)
      

  34.   

    这个回答解决了标题的问题,但是实际情况是
    打个比方
    3个不同的按钮(有的可能是别的各不相同的事件),中间有段代码需要调用GenID
    GenID是有参数有返回的,并且调用的GenID之后并且用GenID的返回值去进行接下去的计算
      

  35.   

    按钮中的事件需要处理后的返回值
    Option ExplicitPrivate mblnRunning As Boolean
    Private mCol As New CollectionPrivate Sub Command1_Click()
        Debug.Print "1 clicked"
        Call test(1)
    End SubPrivate Sub Command2_Click()
        Debug.Print "2 clicked"
        Call test(2)
    End SubPrivate Sub Command3_Click()
        Debug.Print "3 clicked"
        Call test(3)
    End SubPrivate Sub test(ByVal nIn As Long)
        Dim ti As TaskInfo
        Set ti = New TaskInfo
        Call ti.SetUp(nIn)
        Call mCol.Add(ti)
        
        If mblnRunning Then
            Exit Sub
        End If
        
        mblnRunning = True
        
        Do
            Call mCol.Item(1).DoTask
            Call mCol.Remove(1)
        Loop While mCol.Count > 0
        
        mblnRunning = False
    End Sub
      

  36.   

    可以将处理返回值的语句放入TaskInfo类:)
      

  37.   

    应该返回DoTask的运行结果,DoTask稍微改下
    Option ExplicitPrivate mblnRunning As Boolean
    Private mCol As New CollectionPrivate Sub Command1_Click()
        Debug.Print "1 clicked"
        debug.print  test(1)
    End SubPrivate Sub Command2_Click()
        Debug.Print "2 clicked"
        debug.print  test(2)
    End SubPrivate Sub Command3_Click()
        Debug.Print "3 clicked"
        debug.print test(3)
    End SubPrivate Sub test(ByVal nIn As Long) as long
        Dim ti As TaskInfo
        Set ti = New TaskInfo
        Call ti.SetUp(nIn)
        Call mCol.Add(ti)
        
        If mblnRunning Then
            Exit Sub
        End If
        
        mblnRunning = True
        
        Do
            Call mCol.Item(1).DoTask
            Call mCol.Remove(1)
        Loop While mCol.Count > 0
        
        mblnRunning = False
    End Sub