Timer控件是不可重入?对象不可重入?类不可重入?

王二.麻子 2012-05-07 10:52:48
Timer控件.
同时存在两个timer控件,并且处理时间的超过interval的时候,就出现一些比较恶心的情况.
2个timer一个设置20,一个30,正常理解是2个timer处理完循环后,把自己的时间信息显示到自己对应的label,
但是实际情况变化了,只有一个label在更新,另外一个没有更新.

如果你的机器比较快,需要把循环时间调整更长一些,就是设置文本框里面的数字更大些.

我的问题是:是否timer是不可重入的?是否整个工程(或者是活动的这个窗体)里的多个timer也是限制重入,就是一个timer处理过程中
的时候,其他timer是阻塞的?
我的例子如下:

VERSION 5.00
Begin VB.Form Form1
Caption = "Form1"
ClientHeight = 2430
ClientLeft = 60
ClientTop = 345
ClientWidth = 4680
LinkTopic = "Form1"
ScaleHeight = 2430
ScaleWidth = 4680
StartUpPosition = 3 '窗口缺省
Begin VB.CommandButton Command2
Caption = "Start"
Enabled = 0 'False
Height = 495
Left = 2880
TabIndex = 4
Top = 720
Width = 1575
End
Begin VB.CommandButton Command1
Caption = "Stop"
Height = 495
Left = 2880
TabIndex = 3
Top = 1320
Width = 1575
End
Begin VB.TextBox Text1
Height = 270
Left = 2040
TabIndex = 0
Text = "500"
Top = 240
Width = 975
End
Begin VB.Timer Timer2
Interval = 30
Left = 0
Top = 960
End
Begin VB.Timer Timer1
Interval = 20
Left = 0
Top = 1440
End
Begin VB.Label Label3
AutoSize = -1 'True
Caption = "设置一个值,500-60000"
Height = 180
Left = 0
TabIndex = 5
Top = 240
Width = 1800
End
Begin VB.Label Label2
AutoSize = -1 'True
Caption = "Label2"
Height = 180
Left = 480
TabIndex = 2
Top = 960
Width = 540
End
Begin VB.Label Label1
AutoSize = -1 'True
Caption = "Label1"
Height = 180
Left = 480
TabIndex = 1
Top = 1440
Width = 540
End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit
Dim bStop As Boolean
Dim lCount As Long
Private Sub Command1_Click()
bStop = True
Timer1.Enabled = False
Timer2.Enabled = False
Command1.Enabled = False
Command2.Enabled = True
End Sub

Private Sub Command2_Click()
bStop = False
Timer1.Enabled = True
Timer2.Enabled = True
Command1.Enabled = True
Command2.Enabled = False
End Sub

Private Sub Form_Load()
lCount = Val(Text1.Text)
End Sub

Private Sub Text1_Change()
If Not bStop Then
MsgBox "先停止那两个计时器"
Else
lCount = Val(Text1.Text)
End If
End Sub

Private Sub Timer1_Timer()
Dim i, j, k, l
k = Timer
For i = 1 To lCount
For j = 1 To lCount
l = j
If bStop Then Exit Sub
DoEvents
Next j
Next i
Label1.Caption = Timer & " " & Timer - k
End Sub

Private Sub Timer2_Timer()
Dim i, j, k, l
k = Timer
For i = 1 To lCount
For j = 1 To lCount
l = j
If bStop Then Exit Sub
DoEvents
Next j
Next i
Label2.Caption = Timer & " " & Timer - k
End Sub
...全文
526 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2012-05-15
  • 打赏
  • 举报
回复
其实就是使用虚拟机的思路。
嗷嗷叫的老马 2012-05-09
  • 打赏
  • 举报
回复
你这个问题应该从你的程序流程里进行改进.

两个动画显示,可以看作一个时间片中在两个不同区域显示各自不同的图片.

这样的话你可以写一个图片对象,功能是根据输入的时间戳切换不同的图片.

然后用一个定时器或循环,将当前时间戳(用GetTickCount得到)传入对象实例中即可.

这样的话情况会好很多,代码类似这里这个:

以对象方式管理大量不同频率闪烁灯的思路及接口继承的性能(VB6.0代码)

你将这里的对象的两个状态,改为多状态循环切换,再根据这些状态数值,切换不同的图片即可.
  • 打赏
  • 举报
回复
这是固有情况,没有办法改变。把一个timer做成exe,调用它?
王二.麻子 2012-05-09
  • 打赏
  • 举报
回复
有些歪楼了

我想说的是,多个timer这样的控件在单线程的vb里,因为阻塞有时会出问题而达不到预想的结果.

循环不是为了延迟,只是个例子.

设想这样的情况:
一个程序,用了2个timer分别控制2个动画的显示.正常时两个timer每秒各处理10帧,
在一个动画显示里突然出现了大量数据造成处理很慢(timer1),这个时候,处理快的那个timer2也受到影响,
最终2个timer都是1秒处理2帧.虽然timer2的数据还是那么多...
东方之珠 2012-05-09
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]
引用 7 楼 的回复:

你的问题主要是 DoEvents 而不是 Timer!!!

去掉DoEvents确实有改观了.
不去掉是一个timer始终运行,另外一个没有运行.
去掉之后是两个timer交替运行,

在只用一个timer的时候,循环的延时效果是800多毫秒,
在使用2个timer的时候,2个timer交替运行,每个timer循环还是800多毫秒,但是这800毫秒期间……
[/Quote]
你犯了一个低级错误,Timer计时不能用DoEvents,计时不准确暂且不说,CPU将控制权转移,你的Timer就不行了。Timer不是循环,在超级快速循环中用DoEvents是正确的,但也要综合考虑你的程序占用CPU时间的情况,如果占用CPU时间不多,还是可以不用DoEvents的。
东方之珠 2012-05-09
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]
SetTimer肯定是单线程的,建议试试参考这个代码改成timeSetEvent的试试。实在不行的话就要考虑用多线程来弄。


VB code

'This project requires a Form and a Module
'On the form, there should be one command button (Command1)
'and one Timer (T……
[/Quote]
同意。我就经常用timeSetEvent编程,其内部实现是多线程的,不受外界任何影响;缺点是:程序搞不好的话,只能编译成P代码运行,而不能编译成本地代码运行。
推荐使用制作多线程的专业控件ThreadFactory.exe(CSDN资源上可以下载)

王二.麻子 2012-05-09
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

你的问题主要是 DoEvents 而不是 Timer!!!
[/Quote]
去掉DoEvents确实有改观了.
不去掉是一个timer始终运行,另外一个没有运行.
去掉之后是两个timer交替运行,

在只用一个timer的时候,循环的延时效果是800多毫秒,
在使用2个timer的时候,2个timer交替运行,每个timer循环还是800多毫秒,但是这800毫秒期间另外一个timer还是被阻塞的.
Tiger_Zhao 2012-05-09
  • 打赏
  • 举报
回复
明显的设计问题!
难道 RTS 游戏几百个单位每个都定义一个定时器?这样的设计绝对要崩溃的!

一个定时器,每次将所有动画的当前帧取得后一起刷新。
最好每个动画的所有帧预先运算好,这样定时中只需要显示就可以了。
如果需要动态计算,那么单帧运算过程中间就需要计时,超过一定时间就暂停,本次不刷新,让别的动画能够正常刷新;然后下次从暂停点开始运算。需要给运算过程提供一个私有的“堆栈”,难度不大。
of123 2012-05-09
  • 打赏
  • 举报
回复
不需要两个 Timer。

用一个就可以,把间隔设置成两个事件间隔的最大公约数。在 OnTimer 事件中根据计数的值来判断是哪一个到时,就处理哪一个;如果恰好两个都到时,就挨个处理。

赵4老师 2012-05-09
  • 打赏
  • 举报
回复
难道多线程就不互相影响吗?
王二.麻子 2012-05-08
  • 打赏
  • 举报
回复
目的不是求一个高精度的timer,而是timer在使用中有些问题.

如果用了多个timer,有一个timer不知道处理时间有多长,或者就是仅仅一次延迟执行(执行时间很长或不定),就有可能造成另外一个timer不稳定,这样也许程序也跑的不稳定了.

Tiger_Zhao 2012-05-08
  • 打赏
  • 举报
回复
把两个 DoEvents 语句去掉就可以了。
DoEvents 使用不当!
Tiger_Zhao 2012-05-08
  • 打赏
  • 举报
回复
你的问题主要是 DoEvents 而不是 Timer!!!
  • 打赏
  • 举报
回复
似乎是的……
单线程就这个样子啦……
贝隆 2012-05-07
  • 打赏
  • 举报
回复
VB的Timer控件精度有限,试一试这个
http://download.csdn.net/detail/veron_04/3517180
worldy 2012-05-07
  • 打赏
  • 举报
回复
VB中的定时器为单线程运行,当时间到,但是程序还在处理别的事情,定时消息会被吞没

LZ的定时时间值太短,单个定时器经常最小的定时时间也就是12-20ms,再小也没有用
bcrun 2012-05-07
  • 打赏
  • 举报
回复
SetTimer肯定是单线程的,建议试试参考这个代码改成timeSetEvent的试试。实在不行的话就要考虑用多线程来弄。

'This project requires a Form and a Module
'On the form, there should be one command button (Command1)
'and one Timer (Timer1)

'In the form:
Option Explicit
Private Sub Form_Load()
'KPD-Team 2001
'URL: http://www.allapi.net/
'E-Mail: KPDTeam@Allapi.net
Command1.Caption = "Start"
End Sub
Private Sub Form_Unload(Cancel As Integer)
'Stop the timers if they're still counting
timeKillEvent hMMTimer
Timer1.Enabled = False
End Sub
Private Sub Timer1_Timer()
'increment VBTimer
VBTimer = VBTimer + 1
End Sub
Private Sub Command1_Click()
If Command1.Caption = "Start" Then
'Start both timers
Timer1.Interval = 1
Timer1.Enabled = True
hMMTimer = timeSetEvent(1, 0, AddressOf TimerProc, 0, TIME_PERIODIC Or TIME_CALLBACK_FUNCTION)
Command1.Caption = "Stop"
Else
'Stop both timers
timeKillEvent hMMTimer
Timer1.Enabled = False
Command1.Caption = "Start"
'Show result
MsgBox "Timer1_Timer was called " & VBTimer & " times;" & vbNewLine & "TimerProc was called " & MMTimer & " times."
VBTimer = 0
MMTimer = 0
End If
End Sub
'In a module
Option Explicit
Public Const TIME_ONESHOT = 0 'Event occurs once, after uDelay milliseconds.
Public Const TIME_PERIODIC = 1 'Event occurs every uDelay milliseconds.
Public Const TIME_CALLBACK_EVENT_PULSE = &H20 'When the timer expires, Windows calls thePulseEvent function to pulse the event pointed to by the lpTimeProc parameter. The dwUser parameter is ignored.
Public Const TIME_CALLBACK_EVENT_SET = &H10 'When the timer expires, Windows calls theSetEvent function to set the event pointed to by the lpTimeProc parameter. The dwUser parameter is ignored.
Public Const TIME_CALLBACK_FUNCTION = &H0 'When the timer expires, Windows calls the function pointed to by the lpTimeProc parameter. This is the default.
Public Declare Function timeKillEvent Lib "winmm.dll" (ByVal uID As Long) As Long
Public Declare Function timeSetEvent Lib "winmm.dll" (ByVal uDelay As Long, ByVal uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, ByVal uFlags As Long) As Long
Public VBTimer As Long, MMTimer As Long
Public hMMTimer As Long
Sub TimerProc(ByVal uID As Long, ByVal uMsg As Long, ByVal dwUser As Long, ByVal dw1 As Long, ByVal dw2 As Long)
'Increment MMTimer
MMTimer = MMTimer + 1
End Sub

7,785

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧