• Vui lòng đọc nội qui diễn đàn để tránh bị xóa bài viết
  • Tìm kiếm trước khi đặt câu hỏi

Khi nào dùng Timer, khi nào dùng vòng lặp

Các bài viết hướng dẫn, giúp các bạn hiểu và tiếp cận với Visual Basic nhanh hơn
Hình đại diện của người dùng
Dang Minh Du
Thành viên ưu tú
Thành viên ưu tú
Bài viết: 531
Ngày tham gia: T.Tư 02/04/2008 2:08 pm
Đến từ: RGames Team
Has thanked: 3 time
Been thanked: 17 time
Liên hệ:

Khi nào dùng Timer, khi nào dùng vòng lặp

Gửi bàigửi bởi Dang Minh Du » T.Hai 19/05/2008 12:07 pm

Tên bài viết: Khi nào dùng Timer, khi nào dùng vòng lặp
Tác giả: Dang Minh Du
Cấp độ bài viết: Căn bản
Tóm tắt: “Tui” hỏng bík trong diễn đàn có ai chưa bík về cái này không, nhưng ”tui” cũng xin mạo mụi một chút để viết bài này, có lầm lẫn hay sai xót gì thì mấy anh chị với mấy bạn thông cảm ( khì ,khì… :D ).


Control timer và các cấu trúc lặp thì chắc ai cũng bik hết rồi nên “tui” hỏng nói làm gì cho mệt.
Về vác dụng, theo “tui” thì chúng có thể thay thế nhau trong những trường hợp khác nhau:
“Tui” thường hay viết code cho control timer với mục đích thay thế vòng lặp. Ví dụ như tui muốn khi click vào nút CmdStart thì chương trình sẽ thực hiện một công việc là từng Item trong Lst1 sẽ được sao chép qua Lst2 và tất cả code cần thiết sẽ được viết như sau:

Mã: Chọn hết

  1. Private Sub CmdStart _Click()
  2. Timer1.Enabled = True
  3. Lst1.ListIndex = -1
  4. End Sub
  5. Private Sub Timer1_Timer()
  6. Static i As Integer
  7.  If i < 1 Then
  8.        Lst1.ListIndex = Lst1.ListIndex + 1
  9.        Lst2.AddItem Lst1.Text
  10.        i = 0
  11. End If
  12.     If Lst1.ListIndex = Lst1.ListCount - 1 Then
  13.         Timer1.Enabled = False
  14.     End If
  15. End Sub

Nếu dùng For…Next thì code chỉ cần viết ngắn gọn như sau:

Mã: Chọn hết

  1. Private Sub CmdStart _Click()
  2. Dim i As Integer
  3. Lst1.ListIndex = -1
  4. For i = 1 To Lst1.ListCount
  5. Lst1.ListIndex = Lst1.ListIndex + 1
  6. Lst2.AddItem Lst1.Text
  7. Next
  8. i = i + 1
  9. End

Hoặc nếu dùng While…do…loop thì cũng ngắn gọn như sau:

Mã: Chọn hết

  1. Private Sub CmdStart_Click()
  2. List1.ListIndex = 0
  3. List2.AddItem (List1.Text)
  4. Do While (List1.ListIndex < List1.ListCount -1)
  5. List1.ListIndex = List1.ListIndex + 1
  6. List2.AddItem (List1.Text)
  7. Loop
  8. End Sub 

:) Bây giờ tui xin phân tích chút đỉnh:
Theo tui, nếu dùng Control timer thì ta thấy rõ là code cần viết quá dài (gần như gấp đôi vòng lặp),thao tác công việc cũng chậm hơn (tối đa là 0.001s thì làm một lần) đồng thời một điều là chương trình sẽ chạy ì ạch hơn (hao tài nguyên, chiếm nhiều bộ nhớ hơn). Với vòng lặp For...next hay While...do...loop, mọi thứ trở nên đơn giản hơn rất nhiều, chắc chắn chương trình sẽ chạy nhẹ nhàng hơn.
Tuy nhiên, đối với một trường hợp khác, Control timer lại có lợi thế hơn. Cụ thể là chương trình cần thiết một sự đánh động tới thời gian. Ví dụ như chương trình có hiệu ứng lặp đi lặp lại việc di chuyển một Lable tới một địa điểm tính trước (ví dụ từ 0 tới 2880) bằng cách thay đổi toạ độ sau mỗi một biến đổi thời gian (ví dụ 0.001s), Nếu dùng vòng lặp For…next hay While...do...loop thì đối với “tui” là một việc không thể làm được (vấn đề là ở chỗ khoảng thời gian 0.001s, nếu không thì Label sẽ nhảy cái tút từ 0 tới 2880 luôn) (nếu ai làm được thì xin chỉ giáo). Nhưng với Control timer, có thể hiểu nó đóng vai trò như vòng lặp và thực hiện công việc dễ dàng với một đoạn code ngắn ngọn:

Mã: Chọn hết

  1. Private Sub Timer1_Timer()
  2. Static i As Integer
  3. If i < 1 Then
  4.   Lbl1.Left = Lbl1.Left + 1
  5.   i = 0
  6. End If
  7.     If Lbl1.Left > 2880 Then
  8.       Lbl1.Left = 0
  9.     End If
  10. End Sub

:) Xin mọi ngươì cho ý kiến!
Sửa lần cuối bởi Dang Minh Du vào ngày T.Năm 22/05/2008 4:00 pm với 1 lần sửa.


~°Dòng Sông Mùa Thu°~
Studying...!

QuangHoa
Guru
Guru
Bài viết: 542
Ngày tham gia: T.Năm 27/03/2008 9:02 am
Đến từ: Quê hương Đại tướng Võ Nguyên Giáp
Been thanked: 5 time
Liên hệ:

Re: Khi nào dùng Timer, khi nào dùng vòng lặp

Gửi bàigửi bởi QuangHoa » T.Năm 22/05/2008 7:55 am

Khi sử dụng thì có đôi khi nó giống nhau, vì đều có thể ứng dụng để bắt chương trình thực hiện những lệnh giống nhau.
Điểm khác biệt lớn nhất giữa Timer và For là

FOR Không hạn chế thời gian. Còn Timer hạn chế thời gian cho một lần thực hiện chương trình.
Xét ví dụ sau

Mã: Chọn hết

  1. Private Sub Command1_Click()
  2. s = 0
  3. For i = 1 To 100
  4.         s = s + i
  5. Next
  6. Me.Print s
  7. End Sub
  8.  

Hãy so sánh nó với

Mã: Chọn hết

  1. Dim s, i As Long
  2.  
  3. Private Sub Form_Load()
  4. s = 0
  5. i = 0
  6. Timer1.Interval = 100
  7. End Sub
  8.  
  9. Private Sub Timer1_Timer()
  10. i = i + 1
  11. s = s + i
  12. If i = 100 Then
  13.     Timer1.Interval = 0
  14.     Me.Print s
  15. End If
  16. End Sub

Có thể thấy kết quả. Ở trên sau khi bấm Command thì kết quả có tức thời còn bên Timer thì không.
Xét ví dụ khác

Mã: Chọn hết

  1. For i = 1 To 100
  2.         call hamvidu
  3. Next

Mã: Chọn hết

  1. Private Sub Timer1_Timer()
  2. i = i + 1
  3. call hamvidu
  4. if i=100 then timer.inteval =0
  5.    
  6. End Sub

Thì chưa biết chắc chuyện gì xảy ra vì còn phụ thuộc xem thời gian thực hiện hàm vidu là bao lâu nửa.
Thêm ví dụ. Ví dụ như trình bày trong Slizeshow (như trong Powper Poit vậy mà)
Nếu dùng For
Phải khai báo

Mã: Chọn hết

  1. Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Sử dụng

Mã: Chọn hết

  1. For i = 1 To 100
  2.     bieudienhinh
  3.     Sleep 100
  4. Next

Còn với timer

Mã: Chọn hết

  1. Private Sub Timer1_Timer()
  2.     bieudienhinh
  3. End Sub

Trả lời câu hỏi trên cùng Khi muốn tính toán, muốn làm một việc gì đó bên trong chương trình ta dùng vòng lặp. Khi cần biểu diễn trước người dùng một cái gì đó mà đòi hỏi phải dừng chương trình trể lại để còn kịp xem hoặc tronh những phần mềm về thời gian, ta dùng timer.
P/S Dang Minh Du sửa lại bài viết nhớ dùng thẻ code nhé

Mã: Chọn hết

  1. [code=vb] Thẻ Code=vb[/code]
朋友
这些年一个人风也过雨也走,有过泪有过错还记得坚持什么。
真爱过才会懂会记没会回手,终有梦中有你在心中。
朋友一生一起走那些日子不再有,一句话一辈子一生情一杯九。
朋友不曾孤单过一声朋友你会懂,还有伤还有痛还要走还有我。

Hình đại diện của người dùng
playgemboy
Thành viên danh dự
Thành viên danh dự
Bài viết: 289
Ngày tham gia: CN 13/04/2008 6:10 am
Đến từ: Bình Phú, Quận 6, TP.HCM
Been thanked: 1 time
Liên hệ:

Re: Khi nào dùng Timer, khi nào dùng vòng lặp

Gửi bàigửi bởi playgemboy » T.Bảy 31/05/2008 8:10 pm

Cái bài của Minh Dự không tốt cho lắm, nếu chỉ biết chung chung như vậy mà ko giải thích cặn kẽ thì một bài hướng dẫn như vầy sẽ chỉ là cho người mới học có phần bị rối. Mình xin đóng góp một số ý kiến (bạn kêu đóng góp mà :D)
-Khi trình bày một bài Tut, bạn không nên có những từ ngữ đùa cợt, nên viết đúng chính tả (vì đây là bài để cho người khác đọc để học hỏi chứ không phải đọc cho vui), nên xưng hô một cách lịch sự. (vì có thể người đọc sẽ lớn tuổi hơn bạn, họ sẽ phản cảm đấy).Nên trình bày theo kiểu cây phân cấp, như thế sẽ dễ theo dõi dễ hiểu hơn.
-Đa số những điều bạn hiểu là đúng nhưng có vài điều mình không đồng tình:
Theo tui, nếu dùng Control timer thì ta thấy rõ là code cần viết quá dài (gần như gấp đôi vòng lặp),thao tác công việc cũng chậm hơn (tối đa là 0.001s thì chạy code một lần) đồng thời một điều là chương trình sẽ chạy ì ạch hơn (hao tài nguyên, chiếm nhiều bộ nhớ hơn)

-> ai nói với bạn là nó chạy ì ạch hơn ,hao tốn tài nguyên hơn nhỉ?
+thử so sánh với For xem. khi dùng For để làm công việc nào đó, máy sẽ xử lý hết tốc độ mà CPU cung cấp->tốn hơn chứ.
+Bạn nói rằng nó chạy ì ạch? đó là do bạn chưa biết lúc nào sử dụng nó thôi, đặc thù của Timer thì đơn vị Inteval là 0.001 giây, khoảng thời gian giữa vòng lặp là cố định khi đã set inteval (không có sự nhanh hơn hay chậm hơn khi chạy chương trình ở hai máy khác nhau). Với một dòng code khi chạy bằng timer và Vòng lặp thì vòng lặp sẽ xử lý nhanh hơn, bù lại nó hao tốn nhiều CPU hơn.
->để so sánh, ta hãy làm một ví dụ: Set inteval của một timer là 1 (0.001 giây, nhanh nhất mà timer có thể), tạo một vòng lặp (kiểu gì cũng chấp), trong vòng lặp đặt hàm Sleep(1) để nó ngưng 0.001 giây. Như vậy là cả hai bên đều có thời gian giữa hai vòng lặp bằng nhau rồi nhé! Bạn thử cho một đoạn code vào giữa xem?Mình chắc chắn là bên Vòng lặp sẽ làm cho CPU của bạn lên max (hay ít nhất là cũng cao hơn bên Timer).
- Code ví dụ của bạn có chỗ sai (do bạn code theo cách nghĩ của bạn).
+Code ví dụ thứ nhất(sao chép các Item), bạn nghĩ nó chậm do bạn không biết cách code sao cho tối ưu. Lẽ ra chỉ cần vậy thôi:

Mã: Chọn hết

  1. Private Sub Command1 _Click()
  2. Timer1.Enabled = True
  3. End Sub
  4. Private Sub Timer1_Timer()
  5. Static i As Integer
  6. If i < List1.ListCount Then List2.AddItem List1.List(i) Else Timer1.Enabled = False
  7.  i = i + 1
  8. End Sub

+Code ví dụ thứ 2, đáng ra chỉ có vầy thôi :

Mã: Chọn hết

  1. Private Sub Command1_Click()
  2. For i = 0 To List1.ListCount - 1
  3.     List2.AddItem List1.List(i)
  4. Next i
  5. End Sub

nhưng bạn lại viết quá dài, lại thừa nữa :

Mã: Chọn hết

  1. Private Sub CmdStart _Click()
  2. Dim i As Integer
  3. Lst1.ListIndex = -1
  4. For i = 1 To Lst1.ListCount
  5. Lst1.ListIndex = Lst1.ListIndex + 1
  6. Lst2.AddItem Lst1.Text
  7. Next 'chấp nhận được, nhưng tốt hơn là Next i để tránh lỗi khi bạn dùng vòng lặp trong vòng lặp (trong For i lại có For j nữa....)
  8. i = i + 1 '-> thừa, khi Next i thì máy đã tự động cộng thêm
  9. End

-
Nhưng với Control timer, có thể hiểu nó đóng vai trò như vòng lặp và thực hiện công việc dễ dàng với một đoạn code ngắn ngọn..
-> bạn vừa nói là nó tốn code hơn, sao giờ lại nói là nó gọn hơn? ,rõ ràng là bạn chỉ nhận xét chủ quan theo từng trường hợp.
Mình khuyên bạn nên viết những bài Tut mà mình đã hiểu kĩ vẫn đề, không nên post những bài Tut quá sơ sài (đôi khi chỉ nhằm mục đích tăng số bài viết-> vô ích, nặng diễn đàn, gây cho khách viếng thăm có cảm giác diễn đàn không có chất lượng bài viết tốt.)
Việc nói kĩ hơn về sự khác biệt và cách sử dụng thì giongto và quanghoa đã nói.
Trên đây là các ý kiến chủ quan của mình về Bài Tut của Minh Du, mong rằng Minh Du hiểu (đừng nghĩ tui lên mặt nha, đóng góp thôi nhá :D ).
(lưu ý chữ Interval mình viết thành Inteval cho nhanh, do gõ theo kiểu telex)
Sửa lần cuối bởi playgemboy vào ngày T.Bảy 07/06/2008 3:27 pm với 1 lần sửa.
<I Come Back>

Hình đại diện của người dùng
delta_hung1992
Thành viên năng nổ
Thành viên năng nổ
Bài viết: 81
Ngày tham gia: T.Năm 06/11/2008 10:51 pm

Re: Khi nào dùng Timer, khi nào dùng vòng lặp

Gửi bàigửi bởi delta_hung1992 » T.Sáu 14/08/2009 10:58 pm

Em xin có chút ý kiến (nếu sai thì mong mọi người bỏ qua [-O< )
- Theo em nghĩ, timer không phải là một vòng lặp: về nguyên tắc, vòng lặp chỉ thực hiện một đoạn code chỉ khi thỏa mãn một điều kiện nào đó, trong khi đó timer thực hiện các dòng code của nó liên tục và chỉ dừng lại khi qua một khoảng thời gian nhất định. Như vậy chỉ có thể coi timer là một vòng lặp vô hạn mà thôi. Tuy vậy, hạn chế của timer đó là interval, thấp nhất là 1 mili giây, trong khi đó, nếu dùng vòng lặp thì có khi chỉ mất có 1/1000000s (một phần triệu giây), nhanh hơn timer rất nhiều (có những bộ vi xử lý còn có thể xử lý nhanh hơn)
- Về câu hỏi cho một Label di chuyển em xin trả lời như sau:
+ Nếu dùng timer: label sẽ di chuyển đều đặn, tuy nhiên trong trường hợp tính toán quá phức tạp, tốc độ của label sẽ giảm đi, đồng nghĩa với việc ứng dụng sẽ chạy sai lệch về tốc độ (nếu ứng dụng là game thì sẽ giảm tốc độ trò chơi xuống, ảnh hưởng rất lớn đến gameplay lẫn sự kiên nhẫn của người chơi). Hơn nữa, nếu trường hợp đó xảy ra đồng nghĩa với việc người dùng sẽ thấy độ giật của ứng dụng, Label chạy tuy đều nhưng giật => Đau mắt
+ Nếu dùng vòng lặp: tốt nhất nên dùng vòng lặp Do while Doevents .... Loop. Theo như mọi người biết, vòng lặp này buộc ứng dụng quay về thời đoạn idle, giúp giảm tải tính toán. Đồng thời định nghĩa một biến có tên là time_step theo kiểu Double:

Mã: Chọn hết

  1. Dim time_step as Double 'Định nghĩa biến time_step
  2. Private Sub Form_Load()
  3.  Me.Show
  4.  Me.Refresh
  5.  ........
  6.  Do while DoEvents
  7.   ........
  8.   Label1.Move Label1.left - 250 * time_step   'Di chuyển Label
  9.   ........
  10.  Loop
  11.  

Chúng ta có công thức như sau:

Mã: Chọn hết

  1. time_step = 16 / FPS

Với FPS là "số khung hình trên giây" (Frame Per Second)
Làm như vậy thì trong mọi khoảng thời gian (realtime) như nhau, label move được một quãng đường bằng nhau trong mọi trạng thái hoạt động của chương trình
Ví dụ: Cứ 1s label move được một đoạn là 2000 pixel chẳng hạn.
Ta có công thức:
Khoảng delay của timer = khoảng interval của timer đó + khoảng thời gian máy xử lý code của timer
Nếu dùng timer vào lúc máy đang hoạt động mạnh (CPU >= 90%) thì khoảng thời gian máy xử lý code của timer tăng lên => label di chuyển chậm => :((
Nếu dùng timer vào lúc máy đang hoạt động yếu (CPU <= 29%) thì label sẽ di chuyển hết sức mượt mà (hệt như xem 3D move vậy)

Nếu ai có thắc mắc về bài viết hay hỏi về cách tính FPS thì em sẵn sàng giải đáp. Chúc mọi người thành công ;)
Keep moving forward


Quay về “[VB] Bài viết hướng dẫn”

Đang trực tuyến

Đang xem chuyên mục này: Không có thành viên nào trực tuyến.0 khách