Hàm tính tổng theo mầu ô, mầu Font chữ

Liên hệ QC

NHG

Thành viên hoạt động
Tham gia
15/1/07
Bài viết
148
Được thích
126
[/CODE] Đôi khi trong công việc, các bạn cần tính tổng theo mầu của ô, hoặc mầu của Font chữ, trong bài viết này mình xin chia sẻ với các bạn mấy hàm tự tạo để tính tổng theo mầu, đếm theo mầu. Trong đó:

SumColor (Vùng tính tổng, ô điều kiện) : Hàm tính tổng theo mầu của ô
SumFontColor (Vùng tính tổng, ô điều kiện) : Hàm tính tổng theo mầu của Font chữ

CountColor (Vùng dữ liệu, ô điều kiện) : Hàm đếm theo mầu của ô điều kiện
CountFontColor (Vùng dữ liệu, ô điều kiện) : Hàm đếm theo mầu của Font chữ

Chi tiết cách dùng ở trong File đính kèm, nếu bạn nào muốn dùng dạng Add-ins thì tìm Add-ins MyVTV có tích hợp sẵn các hàm này nhé
Mã:
Function ColorCell(xlRange As Range)
    ColorCell = xlRange.Cells(1, 1).Interior.Color
End Function

Function ColorFont(xlRange As Range)
    ColorFont = xlRange.Cells(1, 1).Font.Color
End Function

Function CountColor_VungDL_oDieuKien(rData As Range, cellRefColor As Range) As Long
    Dim indRefColor As Long
    Dim cellCurrent As Range
    Dim cntRes As Long

    Application.Volatile
    cntRes = 0
    indRefColor = cellRefColor.Cells(1, 1).Interior.Color
    For Each cellCurrent In rData
        If indRefColor = cellCurrent.Interior.Color Then
            cntRes = cntRes + 1
        End If
    Next cellCurrent

    CountColor_VungDL_oDieuKien = cntRes
End Function

Function SumColor_VungTinhTong_oDieuKien(rData As Range, cellRefColor As Range)
    Dim indRefColor As Long
    Dim cellCurrent As Range
    Dim sumRes

    Application.Volatile
    sumRes = 0
    indRefColor = cellRefColor.Cells(1, 1).Interior.Color
    For Each cellCurrent In rData
        If indRefColor = cellCurrent.Interior.Color Then
            sumRes = WorksheetFunction.Sum(cellCurrent, sumRes)
        End If
    Next cellCurrent

    SumColor_VungTinhTong_oDieuKien = sumRes
End Function

Function CountFontColor_VungDL_oDieuKien(rData As Range, cellRefColor As Range) As Long
    Dim indRefColor As Long
    Dim cellCurrent As Range
    Dim cntRes As Long

    Application.Volatile
    cntRes = 0
    indRefColor = cellRefColor.Cells(1, 1).Font.Color
    For Each cellCurrent In rData
        If indRefColor = cellCurrent.Font.Color Then
            cntRes = cntRes + 1
        End If
    Next cellCurrent

    CountFontColor_VungDL_oDieuKien = cntRes
End Function

Function SumFontColor_VungTinhTong_oDieuKien(rData As Range, cellRefColor As Range)
    Dim indRefColor As Long
    Dim cellCurrent As Range
    Dim sumRes

    Application.Volatile
    sumRes = 0
    indRefColor = cellRefColor.Cells(1, 1).Font.Color
    For Each cellCurrent In rData
        If indRefColor = cellCurrent.Font.Color Then
            sumRes = WorksheetFunction.Sum(cellCurrent, sumRes)
        End If
    Next cellCurrent

    SumFontColor_VungTinhTong_oDieuKien = sumRes
End Function
 

File đính kèm

  • TinhTongTheoMau.xlsm
    19 KB · Đọc: 33
[/CODE] Đôi khi trong công việc, các bạn cần tính tổng theo mầu của ô, hoặc mầu của Font chữ, trong bài viết này mình xin chia sẻ với các bạn mấy hàm tự tạo để tính tổng theo mầu, đếm theo mầu. Trong đó:

SumColor (Vùng tính tổng, ô điều kiện) : Hàm tính tổng theo mầu của ô
SumFontColor (Vùng tính tổng, ô điều kiện) : Hàm tính tổng theo mầu của Font chữ

CountColor (Vùng dữ liệu, ô điều kiện) : Hàm đếm theo mầu của ô điều kiện
CountFontColor (Vùng dữ liệu, ô điều kiện) : Hàm đếm theo mầu của Font chữ

Chi tiết cách dùng ở trong File đính kèm, nếu bạn nào muốn dùng dạng Add-ins thì tìm Add-ins MyVTV có tích hợp sẵn các hàm này nhé
Mã:
Function ColorCell(xlRange As Range)
    ColorCell = xlRange.Cells(1, 1).Interior.Color
End Function

Function ColorFont(xlRange As Range)
    ColorFont = xlRange.Cells(1, 1).Font.Color
End Function

Function CountColor_VungDL_oDieuKien(rData As Range, cellRefColor As Range) As Long
    Dim indRefColor As Long
    Dim cellCurrent As Range
    Dim cntRes As Long

    Application.Volatile
    cntRes = 0
    indRefColor = cellRefColor.Cells(1, 1).Interior.Color
    For Each cellCurrent In rData
        If indRefColor = cellCurrent.Interior.Color Then
            cntRes = cntRes + 1
        End If
    Next cellCurrent

    CountColor_VungDL_oDieuKien = cntRes
End Function

Function SumColor_VungTinhTong_oDieuKien(rData As Range, cellRefColor As Range)
    Dim indRefColor As Long
    Dim cellCurrent As Range
    Dim sumRes

    Application.Volatile
    sumRes = 0
    indRefColor = cellRefColor.Cells(1, 1).Interior.Color
    For Each cellCurrent In rData
        If indRefColor = cellCurrent.Interior.Color Then
            sumRes = WorksheetFunction.Sum(cellCurrent, sumRes)
        End If
    Next cellCurrent

    SumColor_VungTinhTong_oDieuKien = sumRes
End Function

Function CountFontColor_VungDL_oDieuKien(rData As Range, cellRefColor As Range) As Long
    Dim indRefColor As Long
    Dim cellCurrent As Range
    Dim cntRes As Long

    Application.Volatile
    cntRes = 0
    indRefColor = cellRefColor.Cells(1, 1).Font.Color
    For Each cellCurrent In rData
        If indRefColor = cellCurrent.Font.Color Then
            cntRes = cntRes + 1
        End If
    Next cellCurrent

    CountFontColor_VungDL_oDieuKien = cntRes
End Function

Function SumFontColor_VungTinhTong_oDieuKien(rData As Range, cellRefColor As Range)
    Dim indRefColor As Long
    Dim cellCurrent As Range
    Dim sumRes

    Application.Volatile
    sumRes = 0
    indRefColor = cellRefColor.Cells(1, 1).Font.Color
    For Each cellCurrent In rData
        If indRefColor = cellCurrent.Font.Color Then
            sumRes = WorksheetFunction.Sum(cellCurrent, sumRes)
        End If
    Next cellCurrent

    SumFontColor_VungTinhTong_oDieuKien = sumRes
End Function
Dùng tới 6 Function, nên viết lại 1 Function duy nhất xử lý cả 4 trường hợp trên và cả trường hợp khác màu, hoặc nhiều nhất là 2 Function Sum... và Count...
 
Upvote 0
Dùng tới 6 Function, nên viết lại 1 Function duy nhất xử lý cả 4 trường hợp trên và cả trường hợp khác màu, hoặc nhiều nhất là 2 Function Sum... và Count...
Mấy functions cũng không quan trọng lắm.
Điểm quan trọng là:
- các functions này code khá giống nhau, tức là đối với lập trình bị phạm quy: code lặp lại quá nhiều.
- chả có cái function nào có chú thích nó làm cái gì - tôi dựa vào một cái tên dài thòng để đoán à? (*1), tức là đối với lập trình bị phạm quy: không thân thiện với người dùng (không có tính chất user friendly).

(*1) tên đặt sai, SumByFontColor_BlahBlah mới đúng
oDieuKien là muốn nói cái gì nhỉ?
 
Upvote 0
Dùng tới 6 Function, nên viết lại 1 Function duy nhất xử lý cả 4 trường hợp trên và cả trường hợp khác màu, hoặc nhiều nhất là 2 Function Sum... và Count...
Anh viết thử cho em tham khảo với Anh!

Cảm ơn Anh!
 
Upvote 0
Bạn tự viết được mờ, đầu tiên viết count theo màu ô hoặc màu font trước cho quen rồi phát triển thêm
Em tự viết thử!
PHP:
Function dem_mau_o(range_data As Range, criterial As Range) As Long
    Dim datax As Range
    Dim xcolor As Long
xcolor = criterial.Interior.ColorIndex
For Each datax In range_data
    If datax.Interior.ColorIndex = xcolor Then
        dem_mau_o = dem_mau_o + 1
    End If
Next datax
End Function
 
Upvote 0
Em tự viết thử!
PHP:
Function dem_mau_o(range_data As Range, criterial As Range) As Long
    Dim datax As Range
    Dim xcolor As Long
xcolor = criterial.Interior.ColorIndex
For Each datax In range_data
    If datax.Interior.ColorIndex = xcolor Then
        dem_mau_o = dem_mau_o + 1
    End If
Next datax
End Function
Thêm tham số thứ 3 tùy chọn đếm màu ô hoặc màu Font chữ
 
Upvote 0
Thêm tham số thứ 3 tùy chọn đếm màu ô hoặc màu Font chữ
Anh có thể gợi ý tham số thứ 3 được không Anh?
Tham số thứ 3 em cho kiểu boolean?(TRUE/FALSE), ví dụ như chọn TRUE sẽ đếm thêm màu của chữ, FALSE là ngược lại.

Em cảm ơn Anh!
 
Upvote 0
Anh có thể gợi ý tham số thứ 3 được không Anh?
Tham số thứ 3 em cho kiểu boolean?(TRUE/FALSE), ví dụ như chọn TRUE sẽ đếm thêm màu của chữ, FALSE là ngược lại.

Em cảm ơn Anh!
Đúng rồi, thêm từ khóa Optional
Function dem_mau_o(range_data As Range, criterial As Range, Optional bFontColor As Boolean = True) As Long
Nếu thêm tùy chọn giống hoặc khác thêm tham số thứ 4
Function dem_mau_o(range_data As Range, criterial As Range, Optional bFontColor As Boolean = True, Optional bLike As Boolean = True) As Long
 
Upvote 0
Nếu bạn chỉ muốn code theo truyền thống GPE thì không nên đọc tiếp.
Chỉ đọc tiếp khi bạn muốn code theo tiêu chuẩn chung của lập trình.

Đầu tiên hết, bạn phải xác định cái function nó làm gì. Khi xác định xong thì đặt tên hàm và ghi vào chú thích
Function AggregateByColor
' trả về Sum, hoặc Count các ô trong vùng theo màu

Kế đó, cho xác định những tham mà nó cần để tính toán
' vung : range để tính; mau : range tham chiếu màu

Kết hợp cái trên sẽ được:
' trả về Sum, hoặc Count các ô trong vùng range vung theo màu của range mau

Và tiếp theo là các tham để hàm chọn lựa (nếu có thể)
' kieu : 0 = Count, 1 = Sum
' dang : 0 = màu ô, 1 = màu phông

Cuối cùng:

Function AggregateByColor(vung As Range, mau As Range, kieuTong As Long, dangMau As Long)
' trả về Sum, hoặc Count các ô trong vùng range vung theo màu của range mau
' dựa trên các thông số
' kieuTong : 0 = Count, 1 = Sum ; dangMau : 0 = màu ô, 1 = màu phông
Dim cll As Variant, meMau As Long
meMau = BGFontColor(mau, dangMau)
For Each cll In vung
If BGFontColor(cll) = meMau Then AggregateByColor = AggregateByColor + IIF(lkieuTong, cll.Value2, 1)
Next cll
End Function

Private Function BGFontColor(rg As Range, dangMau As Long) As Long
' trả về màu của range rg, nếu rg có nhiều hơn 1 cell thì chỉ dùng cell đầu tiên
' dangMau : 0 = màu ô, 1 = màu phông
If dangMau Then
BGFontColor = rg.Cells(1,1).Interior.Color
Else
BGFontColor = rg.Cells(1,1).Font.Color
End If
End Function

Chú: hàm BGFontColor không nằm trong giải thuật ban đầu. Khi tiến vào viết giải thuật mới tính lại rằng thêm hàm này thì tiện hơn.
 
Upvote 0
Nếu bạn chỉ muốn code theo truyền thống GPE thì không nên đọc tiếp.
Chỉ đọc tiếp khi bạn muốn code theo tiêu chuẩn chung của lập trình.

Đầu tiên hết, bạn phải xác định cái function nó làm gì. Khi xác định xong thì đặt tên hàm và ghi vào chú thích
Function AggregateByColor
' trả về Sum, hoặc Count các ô trong vùng theo màu

Kế đó, cho xác định những tham mà nó cần để tính toán
' vung : range để tính; mau : range tham chiếu màu

Kết hợp cái trên sẽ được:
' trả về Sum, hoặc Count các ô trong vùng range vung theo màu của range mau

Và tiếp theo là các tham để hàm chọn lựa (nếu có thể)
' kieu : 0 = Count, 1 = Sum
' dang : 0 = màu ô, 1 = màu phông

Cuối cùng:

Function AggregateByColor(vung As Range, mau As Range, kieuTong As Long, dangMau As Long)
' trả về Sum, hoặc Count các ô trong vùng range vung theo màu của range mau
' dựa trên các thông số
' kieuTong : 0 = Count, 1 = Sum ; dangMau : 0 = màu ô, 1 = màu phông
Dim cll As Variant, meMau As Long
meMau = BGFontColor(mau, dangMau)
For Each cll In vung
If BGFontColor(cll) = meMau Then AggregateByColor = AggregateByColor + IIF(lkieuTong, cll.Value2, 1)
Next cll
End Function

Private Function BGFontColor(rg As Range, dangMau As Long) As Long
' trả về màu của range rg, nếu rg có nhiều hơn 1 cell thì chỉ dùng cell đầu tiên
' dangMau : 0 = màu ô, 1 = màu phông
If dangMau Then
BGFontColor = rg.Cells(1,1).Interior.Color
Else
BGFontColor = rg.Cells(1,1).Font.Color
End If
End Function

Chú: hàm BGFontColor không nằm trong giải thuật ban đầu. Khi tiến vào viết giải thuật mới tính lại rằng thêm hàm này thì tiện hơn.
BGFontColor(cll) = meMau Then AggregateByColor = AggregateByColor + IIF(lkieuTong, cll.Value2, 1)
Next cll
End Function
Bác có thể giải thích ý trên được không? Em đọc em chưa hiểu lắm . tại sao là.value2.
Bài đã được tự động gộp:

PHP:
BGFontColor(cll) = meMau Then AggregateByColor = AggregateByColor + IIF(lkieuTong, cll.Value2, 1)
Next cll
End Function
 
Upvote 0
BGFontColor(cll) = meMau Then AggregateByColor = AggregateByColor + IIF(lkieuTong, cll.Value2, 1)
Next cll
End Function
Bác có thể giải thích ý trên được không? Em đọc em chưa hiểu lắm . tại sao là.value2.
Chỉ tính tổng thì dùng value2 nhanh hơn value vài phần tỷ giây :p
Value và Value2 đều là thuộc tính trả về trị của range. Value2 lấy cái trị nằm ngay trong range, Value lấy cũng lấy cái trị đó những qua kiểu riêng của từng cell. Vì vậy, Value2 nhanh hơn. Tuy nhiên vì trị này không qua kiểu riêng của cell cho nên gặp những loại kiểu như Date, Time thì nó sẽ trả về kiểu Double.
Kết luận:
Dùng Value2 nhanh hơn (*1). Nhưng chỉ nên dùng nếu chắc chắn là mình chỉ lấy giá trị số trong range. Nếu bạn đổ Range ra mảng rồi đổ lại vào nơi khác thì chỉ nên dùng Value. Bởi vì với Value2 các ô dạng DateTime sẽ bị thành số hết.

(*1) với cấu hình máy tính hiện nay, chỉ nhanh hơn vài phần tỷ giây cho mỗi ô. Nếu bạn đổ một triệu ô ra mảng thì chỉ nhanh hơn vài phần ngàn giây. Chả bỏ công debug.

(*2) ở trên tôi dùng Value2 vì tôi chắc chắn là mình chỉ muốn trị số trong ô.
 
Upvote 0

@NHG, @huonglien1901

Bạn có thể tham khảo thêm hàm tổng + hàm đếm:

HÀM UDF TỔNG VỚI ĐIỀU KIỆN MÀU PHÔNG HOẶC NỀN

với Hàm S_SumF

Hướng dẫn sử dụng hàm:
S_SumF(Cells,[WithFontColor],[WithBackgroundColor],[DisplayFormat],[Title])
Vị tríTham sốKiểuChức năng
1​
CellsVùng cần tổngNhận vùng cần tổng
2​
WithFontColorCó/KhôngTổng với Font màu
3​
WithBackgroundColorCó/KhôngTổng với màu nền
4​
DisplayFormatCó/KhôngXét màu đã định dạng có điều kiện
5​
TitleChuỗiChuỗi bất kì do người dùng đặt (Nếu không thì trả về giá trị là "Tổng:")

Hướng dẫn nhập nhiều vùng:
Với hàm S_Cells: S_SumF(S_Cells(A1:A20, B3:B20))

Cách viết hàm nhanh, gõ vào ô chuỗi =S_SumF và ấn tổ hợp phím Ctrl+Shift+A
Viết nhanh: =S_SumF(A2)

HÀM ĐẾM S_CountF tương tự hàm S_SumF.

PHP:
Option Explicit

Private Type TypeArguments
  Action As Long
  Cells As Excel.Range
  Caller As Range
  Formula As String
  WithFontColor  As Boolean
  WithBackgroundColor As Boolean
  DisplayFormat As Boolean
  IsCount As Boolean
  Value As Variant
End Type

#If VBA7 Then
  Private Declare PtrSafe Function SetTimer Lib "USER32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As LongPtr, ByVal lpTimerFunc As LongPtr) As Long
  Private Declare PtrSafe Function KillTimer Lib "USER32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
#Else
  Private Declare Function SetTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
  Private Declare Function KillTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long) As Long
#End If
''///////////////////////////////////////////////////////
#If VBA7 And Win64 Then
  Private gTimerID As LongPtr
#Else
  Private gTimerID As Long
#End If
''///////////////////////////////////////////////////////
Private Works() As TypeArguments
Sub test()
  On Error Resume Next
  Dim k%, u%
  u = UBound(Works)
  For k = 1 To u
    Debug.Print Works(k).Action
  Next
End Sub


Function S_CountF( _
             ByVal Cells As Range, _
    Optional ByVal WithFontColor As Boolean = True, _
    Optional ByVal WithBackgroundColor As Boolean = True, _
    Optional ByVal DisplayFormat As Boolean = True, _
    Optional ByVal Title$ = vbNullChar)
  On Error Resume Next
  Dim r As Object, k%, n%, i%, s$, f$, t$
  t = "T" & ChrW(7893) & "ng " & ChrW(273) & ChrW(7871) & "m: "
  s = Cells.Address(0, 0)
  Set r = Application.Caller
  f = r.Formula

  If WithFontColor = False And WithBackgroundColor = False Then
    S_CountF = t & "Ch" & ChrW(7885) & "n " & ChrW(273) & "i" & ChrW(7873) & "u ki" & ChrW(7879) & "n m" & ChrW(224) & "u ph" & ChrW(244) & "ng + n" & ChrW(7873) & "n"
    Exit Function
  Else
    If Title = vbNullChar Then
      S_CountF = t
    Else
      S_CountF = Title
    End If
  End If
  If Cells.Worksheet.ProtectContents Then
    S_CountF = "Protect"
    Exit Function
  End If
  k = UBound(Works)
  For i = 1 To k
    With Works(i)
      If .Formula = f Then
        Select Case .Action
        Case 2: S_CountF = t & .Value: .Action = 3:
          S_SumOrCount_finish k
          Exit Function
        Case Else: .Action = 0: GoTo n
        End Select
        Exit For
      End If
    End With
  Next
  k = k + 1
  ReDim Preserve Works(1 To k)
  With Works(k)
    Set .Caller = r
    Set .Cells = Cells
    .Formula = f
    .WithFontColor = WithFontColor
    .WithBackgroundColor = WithBackgroundColor
    .DisplayFormat = DisplayFormat
    .IsCount = True
  End With
n:
  Set r = Nothing
  If gTimerID = 0 Then
    gTimerID = SetTimer(0&, 0&, 0, AddressOf S_SumOrCount_callback)
  End If
  On Error GoTo 0
End Function

Function S_SumF( _
             ByVal Cells As Range, _
    Optional ByVal WithFontColor As Boolean = True, _
    Optional ByVal WithBackgroundColor As Boolean = True, _
    Optional ByVal DisplayFormat As Boolean = True, _
    Optional ByVal Title$ = vbNullChar)

  On Error Resume Next
  Dim r As Object, k%, n%, i%, s$, f$, t$
  t = "T" & ChrW(7893) & "ng: "
  s = Cells.Address(0, 0)
  Set r = Application.Caller
  f = r.Formula

  If WithFontColor = False And WithBackgroundColor = False Then
    S_SumF = t & "Ch" & ChrW(7885) & "n " & ChrW(273) & "i" & ChrW(7873) & "u ki" & ChrW(7879) & "n m" & ChrW(224) & "u ph" & ChrW(244) & "ng + n" & ChrW(7873) & "n"
    Exit Function
  Else
    If Title = vbNullChar Then
      S_SumF = t
    Else
      S_SumF = Title
    End If
  End If
  If Cells.Worksheet.ProtectContents = True Then
    S_SumF = "Protect"
    Exit Function
  End If
  k = UBound(Works)
  For i = 1 To k
    With Works(i)
      If .Formula = f Then
        Select Case .Action
        Case 2: S_SumF = t & .Value:
          .Action = 3
          S_SumOrCount_finish k
          Exit Function
        Case Else:
          .Action = 0: GoTo n
        End Select
        Exit For
      End If
    End With
  Next
  k = k + 1
  ReDim Preserve Works(1 To k)
  With Works(k)
    Set .Caller = r
    Set .Cells = Cells
    .Formula = f
    .WithFontColor = WithFontColor
    .WithBackgroundColor = WithBackgroundColor
    .DisplayFormat = DisplayFormat
    .IsCount = False
  End With
n:
  Set r = Nothing
  If gTimerID = 0 Then
    gTimerID = SetTimer(0&, 0&, 0, AddressOf S_SumOrCount_callback)
  End If
  On Error GoTo 0
End Function
Private Sub S_SumOrCount_finish(ByVal u%)
  Dim k%
  For k = 1 To u
    If Works(k).Action <> 3 Then
      Exit Sub
    End If
  Next
  If u > 0 Then
    Erase Works
  End If
End Sub
Private Sub S_SumOrCount_callback()
  On Error Resume Next
  Call KillTimer(0&, gTimerID)
  gTimerID = 0
  S_SumOrCount_working
  On Error GoTo 0
End Sub

Private Sub S_SumOrCount_working()
 
  On Error Resume Next
  Dim UB As Integer, a As Object, b As TypeArguments, i&, k&, su As Boolean, Ac As Boolean, v As Variant
  UB = UBound(Works)
  Dim s$
  For i = 1 To UB
    b = Works(i)
    Select Case b.Action
    Case 0
      If b.Caller.Formula = b.Formula Then
        If a Is Nothing Then
          Set a = b.Cells.Parent.Parent.Parent
          su = a.ScreenUpdating
          Ac = a.Calculation
          If su Then a.ScreenUpdating = False
          If Ac = xlCalculationAutomatic Then a.Calculation = xlCalculationManual
        End If

        Works(i).Action = 1
        Call S_CountOrSum(b.Cells, b.Caller, b.WithFontColor, b.WithBackgroundColor, b.DisplayFormat, b.IsCount, v)
        Works(i).Action = 2
        Works(i).Value = v
        b.Caller.Formula = b.Formula
      Else
        Works(i).Action = 3
      End If
    Case 3, 4: k = k + 1
    End Select
n:
  Next
  If k >= UB Then
    Erase Works
  End If
  If Not a Is Nothing Then
    If su And a.ScreenUpdating <> su Then
      a.ScreenUpdating = su
    End If
    If Ac = xlCalculationAutomatic And Ac <> a.Calculation Then
      a.Calculation = Ac
    End If
    Set a = Nothing
  End If
  On Error GoTo 0
End Sub

Function S_Cells(ParamArray Cells()) As Range
  Dim c, r As Range
  For Each c In Cells
    If TypeName(c) = "Range" Then
      If r Is Nothing Then
        Set r = c
      Else
        If r.Parent Is c.Parent Then
          Set r = Union(c, r)
        End If
      End If
    End If
  Next
  Set S_Cells = r
End Function


Private Sub S_CountOrSum( _
             ByVal Cells As Range, _
             ByVal Caller As Range, _
    Optional ByVal WithFontColor As Boolean = True, _
    Optional ByVal WithBackgroundColor As Boolean = True, _
    Optional ByVal DisplayFormat As Boolean = True, _
    Optional ByVal IsCount As Boolean, _
    Optional Value As Variant)
   
  Dim r&, v, c$, c1&, c2&, cell, mCell, cs As Range, w As Worksheet
  Dim cl(), it%, z%, m As Boolean, n As Boolean
  Dim d As Object
  Set d = VBA.CreateObject("Scripting.Dictionary")
  Value = 0
  For Each cell In Cells
    Set mCell = cell.MergeArea
    m = False
    If w Is Nothing Then
      m = True
      Set cs = mCell
      GoSub c
      Set w = cell.Parent
    Else
      GoSub r
    End If
    If m Then
      If DisplayFormat Then
        c1 = cell.DisplayFormat.Interior.Color
        c2 = cell.DisplayFormat.font.Color
      Else
        c1 = cell.Interior.Color
        c2 = cell.font.Color
      End If
      c = IIf(WithBackgroundColor, c1, vbNullString) & "a" & _
          IIf(WithFontColor, c2, vbNullString)
     
      If IsCount Then
        If d.exists(c) Then
          d(c) = Array(d(c)(0) + 1, d(c)(1), d(c)(2))
        Else
          d.Add c, Array(1, c1, c2)
        End If
        Value = Value + 1
      Else
        v = cell.Value
        n = IsNumeric(v)
        If n Then
          Value = Value + v
        End If
        If d.exists(c) Then
          If n Then
            v = d(c)(0) + v
            d(c) = Array(v, d(c)(1), d(c)(2))
          End If
        Else
          If n Then
            d.Add c, Array(v, c1, c2)
          End If
        End If
      End If
    End If
  Next
  If d.Count Then
    r = 1
    For Each cell In d.keys()
      r = r + 1
      With Caller(r, 1)
        .Interior.Color = d(cell)(1)
        .font.Color = d(cell)(2)
        .Value = d(cell)(0)
      End With
    Next
  End If
  Set cell = Caller(2, 1)
  r = cell(1000, 1).End(xlUp).Row - cell.Row + 1
  If r > 0 And r - d.Count > 0 Then
    cell(r + 1, 1).Copy cell(d.Count + 1, 1).Resize(r - d.Count, 1)
  End If
  Set d = Nothing
  Set w = Nothing
  Set cs = Nothing
Exit Sub
r:
  If w Is cell.Parent Then
    m = Intersect(cs, mCell) Is Nothing
    Set cs = Union(cs, mCell)
  Else
    m = True
    For it = 1 To w
      If cl(1, it) Is cell.Parent Then
        Set cs = cl(2, it): m = False
        Exit For
      End If
    Next
    If m Then
      Set cs = mCell
      Set w = cell.Parent
      GoSub c
    Else
      m = Intersect(cs, mCell) Is Nothing
    End If
  End If
Return
c:
  z = z + 1
  ReDim Preserve cl(1 To 2, 1 To z)
  Set cl(1, z) = cell.Parent
  Set cl(2, z) = cs
Return
End Sub
 

File đính kèm

  • S_Sum.xlsm
    37.1 KB · Đọc: 19
Lần chỉnh sửa cuối:
Upvote 0
tham khảo thêm chút nè ...

Bài đăng ngon lành như vậy mà việc tận dụng Application.Volatile của họ cứ như mới biết VBA.
Người không biết sao chép sử dụng sớm phá hỏng CPU. Khiến ứng dụng chậm chạp
Vấn đề nằm ở kinh nghiệm. Không phải bài đăng nằm ở chỗ ngon lành là tốt.


Application.Volatile là dành cho lập trình "cứng".
 
Upvote 0
#13 Cập nhật thêm:
1. Thêm hàm S_CountF
2. Giải thuật hàm bất đồng bộ. Kỹ thuật code VBA mới. Giúp gán giá trị vào ô gõ hàm, sau khi thực hiện tính toán.
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom