bác tuanuni nói thì điều đó ai cũng muốn làm nhưng vấn đề nhiều khi ta chỉ muốn đạt được mục đích nhỏ trước mắt mà thôi chứ các trường hợp khác nó nhiều và lớn lao quá. Nếu 1 fần mềm thương mại mà cứ làm như trước giờ ta vẫn làm thì làm sao mà bán được, thế mới là bác BIN chứ
Tớ cũng nói rồi mà, phần lớn chúng ta quan tới tới mục định nhất định chứ chưa bao quát hết tình huống. Tớ viết bài này lên đây để những chúng ta cùng nâng cao trình độ về lập trình. Đặc biệt không có ý khoe khoang hay chê bai ai (vì bản thân mình chưa là gì).
Khi chúng ta viết ứng ụng trên VB, do bản chất của ngôn ngữ đơn giản, dễ tiếp cận (nhất là với giớp không chuyên) đã giúp và làm cho chúng ta "đơn giản" quá nhiều trong khi viết ứng dụng, vì sự dễ tiếp cận của VB phần nào khiến cho những người mới tiếp cận dễ dẫn đến tính ẩu hoặc cẩu thả khi lập trình. Trong ngôn ngữ C/C++, Pascal (ngôn ngữ tạo ra hệ điều hành, Pascal tạo ra HĐH Mac) thì rất nghiêm ngặt, nếu không khai báo biến thì không thể sử dụng, kiểu dữ liệu chặt chẽ, C/C++ thì lại phân biệt chữ thường chữ hoa,...Nếu ai đã thử nghiệm qua, ban đầu thực sự ngán. Nhưng các chuyên gia nói đó là các ngôn ngữ cho chuyên gia còn VB chưa phải nơi thể hiện đẳng cấp thực sự (về mặt ngôn ngữ).
Điều gì xảy ra nếu chúng ta viết ứng dụng gọi là làm ẩu?
- Về mặt kỹ thuật, làm dư thừa tài nguyên, tràn bộ nhớ, treo máy. Nếu các bạn lập trình trên các ngôn ngữ khác, tạo các DLL dùng chung thì cần cẩn thận từng dòng lệnh. Chúng ta vẫn hay than phiền Excel chạy chậm khi dữ liệu lớn, đó một phần chính là chúng ta làm chưa khoa học+do ẩu dẫn đến lãng phí tài nguyên, bộ nhớ đầy ->chạy chậm. Người bị bệnh cũng vậy, khi phát hiện ra bệnh thường là khi bệnh đã bị nặng rồi, nếu theo dõi điều trị từ trước chắc đã đỡ hơn nhiều.
- Về mặt nghiệp vụ, đây mới là cái thực sự quan trong nhất. Khi chúng ta cần tính một khuản tiền cho N người, với các điều kiện ràng buộc, các tình huống khác nhau. Nếu ít nhất một tình huống ta chưa tìm ra nguy cơ tiềm ẩn về sự sai sót là có. Nếu xảy ra chắc chung ta biết hậu quả với mình như thế nào.
....
Trong cuộc sống, từ việc làm phần nào thể hiện tính người và chính đây cũng sẽ làm ảnh hưởng tới cuộc sống của họ rất nhiều. Tôi nhận thấy, sự cẩn thận là cần cho bất cứ ai đó, người càng giữ trọng trách lớn thì càng phải cẩn thận nhiều từ lời nói đến hành động, rất có thể một sự sai lầm sẽ dấn đến một bước ngoặt của họ. Với việc lập trình, ứng dụng càng lớn thì càng phải cẩn thận từng dòng code.
Có những điều khi chưa xảy ra thì chưa nói. Với tôi, mọi thứ đã xảy ra nên tôi đang phải học nhiều về tính cẩn thận.
He he, Great! Đây là điều lúc nào tôi cũng nói với người lập trình.
Nhưng mà TuanVNUNI cẩn thận quá khi viết:
Dim obj As Object, Object2 As Object Set obj = Nothing
1. Vừa mới khai báo Dim obj As Object xong, chưa creat nó thì ko nhất thiết tự nhiên phải Set obj = Nothing. Chưa hết, thông thường người ta thường Check 1 cái gì đó trước khi thực hiện 1 câu lệnh.
Ví dụ: If Not objCustomer Is Nothing Then Set objCustomer = Nothing.
Tương tự cho việc kill file, close recordset, disconnect dbconnection, v.v...
2. obj là tiếp đầu ngữ, khai báo như vậy ko đúng Namming Convention lắm vì thiếu phần Tên. Ví dụ: objCustomer, objEmployee
3. Object2 chưa được khai báo đúng theo Namming Convention. Vẫn còn tiếp tục cần tính cẩn thận hơn.
4. Có 1 nhầm lẫn là khi viết trong VB tạo nên tính cẩu thả. Như vậy không đúng cho lắm. Thực sự, ở bất cứ môi trường nào, công việc nào cũng đều cần cẩn thận. Viết VB hay Excel mà cẩu thả thì lỗi xảy ra rất... không thể chấp nhận được với những ứng dụng mang tính thương mại cao. Trong VB, khi sử dụng các Windows Resources mà ko biết viết thì cũng treo máy, hết resources như viết trong Visual C thôi. Có rất nhiều ví dụ cho thấy, chạy 100 TRIỆU BẢN GHI thì ko bao giờ chạy nổi. Nhưng có những ví dụ cho thấy máy cấu hình bình thường vẫn có khả năng sử lý với dữ liệu không lồ nói trên. Nhiều khi công nghệ nó quyết định vấn đề này 1 chút nhưng rõ ràng tất cả những cái đó có thể viết trên Delphi, VC hay VB hay những ngôn ngữ khác trên .NET.
5.
Nhưng các chuyên gia nói đó là các ngôn ngữ cho chuyên gia còn VB chưa phải nơi thể hiện đẳng cấp thực sự (về mặt ngôn ngữ).
Vấn đề này thì Tuân lại hoàn toàn nhầm rồi. Cho dù HĐH Windows có được viết = C đi chăng nữa cũng ko ai nói thế cả - rất hạn chế khi đưa ra nhưng tuyên bố như vậy vì mình ko phải là những Micro$oft Experts. Trên rất nhiều diễn đàn đã có những tranh luận tương tự như vậy rồi nhưng ko đi đến đâu cả (ai cũng biết là VC thì gần gũi hơn với ASM và ngôn ngữ máy hơn VB rồi, và khi họ viết sang VB, họ viết y chang như cách viết trên VC) và bây giờ cũng chả còn mấy người trên những diễn đàn đó còn viết những ngôn ngữ đó nữa. Họ chuyển hết lên Visual Studio .NET rồi. Trong khi mình đang tranh luận (dù ko tranh luận thì cũng ko nên nói thế) VB với C++ thì M$ đưa ra Visual Studio 2008 Beta cho Windows Vista, .NET Framework 3.5 Beta rồi. Thôi, ko nói chuyện này nữa vì có thể gây ra đau đầu.
Những đoạn ASM code như thế này cũng được chuyển đổi sang VB một cách hoàn hảo không khác gì viết trong VC.
Mã:
....
;************
;Data storage
dd_nCallStack dd 0 ;WndProc call stack counter
dd_bBypassing dd 0 ;Shutdown flag
dd_lWnd dd 0 ;Window handle
dd_fnEbMode dd 0 ;EbMode function address
dd_fnCallWinProc dd 0 ;CallWindowProc function address
dd_fnSetWinLong dd 0 ;SetWindowsLong function address
dd_fnVirtualFree dd 0 ;VirtualFree function address
dd_fnIsBadCodePtr dd 0 ;ISBadCodePtr function address
dd_objOwner dd 0 ;Owner object address
dd_addrWndProc dd 0 ;Original WndProc address
dd_addrCallback dd 0 ;Callback address
dd_addrTableB dd 0 ;Address of before original WndProc message table
dd_addrTableA dd 0 ;Address of after original WndProc message table
dd_lParamUser dd 0 ;User defined callback parameter
dd_fnDestroyWindow dd 0 ;DestroyWindow function address
dd_SetTimer dd 0 ;SetTimer function address
dd_KillTimer dd 0 ;KillTimer function address
dd_timerID dd 0 ;TimerID returned by SetTimer
;***********
;Thunk start
Align 4
xor eax, eax ;Zero eax, lReturn in the ebp stack frame
xor edx, edx ;Zero edx, bHandled in the ebp stack frame
pushad ;Push all the cpu registers on to the stack
mov ebp, esp ;Setup the ebp stack frame
mov ebx, 012345678h ;dummy Address of the data, patched from VB
xor esi, esi ;Zero esi
inc dword nCallStack ;Increment the WndProc call counter
cmp bBypassing, esi ;bypassing if not zero
jnz _bypass
;Check for dead callback address
push dword addrCallback ;Push the callback address
call near fnIsBadCodePtr ;Check the code is live
jnz _set_bypass ;if non-zero, set bBypassing flag & bypass
cmp fnEbMode, eax ;Check if the EbMode address is set
jz _before ;if zero, user not in IDE
call near fnEbMode ;Determine the IDE state
cmp eax, dword 1 ;If EbMode = 1
je _before ;Running normally
test eax, eax ;If EbMode = 0 then shut down
jnz _bypass ;else on breakpoint
Align 4
_set_bypass:
mov bBypassing, dword M_RELEASE ;set bypass flag indicating result of END
Align 4
_bypass:
call _wndproc ;EbMode = 2, breakpoint... call original WndProc
jmp _return ;Return
....
Đoạn viết bằng VB ... dài hơn nên ko post lên đây được.
Hy vọng Tuân vẫn có tiếp tục những chủ đề như thế này (và hy vọng hơn cả là có nhiều người học được từ những chủ đề như thế này)
Em biện hộ một chút
Dim obj As Object ->Ý nói là khai báo một đối tượng nào đó
Set obj = Nothing ->Ý nói sau n bước nào đó và giải phóng đối tượng, sau đó lại dùng hàm VBA_SUM(obj) để tính đối tượng đó, cố tình tạo tình huống thôi.
Dù sao ví dụ test chưa rõ ràng lắm.
Nhưng các chuyên gia nói đó là các ngôn ngữ cho chuyên gia còn VB chưa phải nơi thể hiện đẳng cấp thực sự (về mặt ngôn ngữ).
Em cũng chỉ dám nói nười khác là "các chuyên gia" đã đánh giá chứ bản thân chưa khẳng định hoàn toàn. Em cũng đã nhận thấy có một số vấn đề mà VB không làm được?
Như ở đây http://www.giaiphapexcel.com/forum/newthread.php?do=newthread&f=31
Nếu làm được anh có thể hướng dẫn giúp.
Em nghĩ đây là chủ đề cũng rất cần mọi người chia sẻ để cùng học hỏi thêm. Với kinh nghiệm của mình, em mong anh tiếp tục chia sẻ cùng mọi người.
Re 1: Cái link mà Tuân đưa hình như là New 1 topic
Nếu là vấn đề Unicode ở MDI caption ko phải là ở vấn đề không lên được tiếng Việt Unicode ở Windows Classic Theme hay Win2k vì ở 2 môi trường này thì cách hiển thị sẽ là khác mà ko dùng theo cách bình thường mà mình vẫn hay làm. Vấn đề khó là vấn đề làm thế nào để quản lý cái vụ khi thì child form maximized và un-maximized cơ. Còn chuyện để nó lên Unicode cho 2 môi trường đó, chỉ cần tìm hiểu 1 chút về vấn đề Unicode trên WinXP Theme, Win2k, Win98 là OK thôi mà. Nhưng vì tớ chưa đặt vấn đề đó lên cao nên chưa làm thôi.
Có 1 trang web nói rất kỹ về vấn đề Unicode này rồi mà.
As you can see from the above Screenshot XP Themes give a nice appearance to controls but they may have undesirable side effects when it comes to Unicode.
If you manage to coerce a Vb ANSI control to display Unicode, you will more than likely lose the Unicode(displays as ???) when a Theme is applied. One exception to this is using a hook and calling API "SetWindowTextW" when you receive the HCBT_ACTIVATE message. This appears to work both with and without a XP Theme.
You can circumvent this behaviour by creating from scratch an API Owner-Draw control where you apply the Theme manually and not via a Manifest file. API 'DrawThemeText' can be called just like DrawTextW where you supply a RECT, Pointer to a Unicode string, and an alignment Flag.
You may also want to fix some of the anomalies(aka bugs) with XP Themes or even add new features. For example you can see from the above screenshot that the button corners are transparent, something you don't get using a Manifest. Using a Manifest a background rectangle is painted(API DrawThemeParentBackground).
If no Theme is available or activated you can drop back to a standard or flat style control and use DrawTextW to output the Unicode text.
Hôm nay xin trình bày với các bạn cách viết hàm có điều kiện cho Excel trong VBA. Hàm VBA_SUMIF
Mã:
[COLOR="Lime"]'Phien ban nay chua chay dung neu criteria su dung ? hoac *[/COLOR]
Function VBA_SUMIF(ByVal test_range, ByVal criteria, Optional ByVal sum_range) As Variant
Dim OperArg 'TO get Array
Dim VT As VbVarType, VT_Test As VbVarType
Dim strOper, StrL2 As String, nOper As Long
Dim nLow As Long, nHigh As Long, i As Long, nLow_Sum As Long, nHigh_Sum As Long
Dim HasSumRange As Boolean
Dim nSUM
VT_Test = VarType(test_range)
If VT_Test <> vbArray And VT_Test <> vbObject And VT_Test <> 8204 Then
'Raise Error
GoTo RaiseErr
End If
VT_sum = VarType(sum_range)
HasSumRange = (VT_sum <> vbError)
If HasSumRange And VT_sum <> vbArray And VT_sum <> vbObject And VT_sum <> 8204 Then
'Raise Error
GoTo RaiseErr
End If
VT = VarType(criteria)
If VT <> vbString And VT <> vbObject Then
'Raise Error
GoTo RaiseErr
End If
If VT = vbObject Then
If criteria Is Nothing Then
'Raise Error
GoTo RaiseErr
End If
End If
OperArg = Array("<>", ">=", "<=", "=", ">", "<", "")
criteria = Trim(criteria)
StrL2 = Left(criteria, 2)
For Each strOper In OperArg
If InStr(StrL2, strOper) > 0 Then
Exit For
End If
Next
nOper = Len(strOper)
criteria = Mid(criteria, nOper + 1, Len(criteria) - nOper)
If strOper = "" Then strOper = "="
On Error GoTo GetcDim
'For Excel.Range
nLow = 1
nHigh = test_range.Rows.Count
GoTo Begin
GetcDim:
'For Array
If VT_Test = 8204 Or VT_Test = vbArray Then
nLow = LBound(test_range, 1)
nHigh = UBound(test_range, 1)
End If
Begin:
On Error GoTo RaiseErr:
VBA_SUMIF = 0
For i = nLow To nHigh
If HasSumRange Then
VT = VarType(sum_range(i))
Else
VT = VarType(test_range(i))
End If
If VT = vbEmpty Or VT = vbError Or VT = vbString Or VT = vbNull Then
GoTo EndFor
End If
If IsTrue(strOper, test_range(i), criteria) Then
If HasSumRange Then
VBA_SUMIF = VBA_SUMIF + sum_range(i)
Else
VBA_SUMIF = VBA_SUMIF + test_range(i)
End If
End If
EndFor:
Next i
EndFunc:
Exit Function
RaiseErr:
VBA_SUMIF = "#N/A"
End Function
Function IsTrue(ByVal strOper As String, ByVal Value1, ByVal Value2) As Boolean
If IsNumeric(Value2) Then Value2 = Val(Value2)
IsTrue = False
If strOper = "=" Then
IsTrue = (Value1 = Value2)
ElseIf strOper = "<>" Then
IsTrue = (Value1 <> Value2)
ElseIf strOper = ">=" Then
IsTrue = (Value1 >= Value2)
ElseIf strOper = "<=" Then
IsTrue = (Value1 <= Value2)
ElseIf strOper = "<" Then
IsTrue = (Value1 < Value2)
ElseIf strOper = ">" Then
IsTrue = (Value1 > Value2)
End If
End Function
Các thủ tục để test trong VBA.
Mã:
Sub Test_VBA_SUMIF_Array()
Dim ValueArg
ValueArg = Array(200, 300, 400)
MsgBox VBA_SUMIF(ValueArg, ">200")
End Sub
Sub Test_VBA_SUMIF_Range()
Dim ValueArg As range
Set ValueArg = range("DOANHTHU") [COLOR="Lime"]'Sheets("Sheet2").Range("F7:F9")[/COLOR]
MsgBox VBA_SUMIF(ValueArg, ">200")
Set ValueArg = Nothing
End Sub
Chữa một chút các bạn sẽ có hàm VBA_COUNTIF. Nâng cao hơn nữa chúng ta có thể viết các hàm SumIfs, CountIfs như trong Excel2007.