Пропустить пустые ячейки в диапазоне

У меня есть код для выбора указанного диапазона и вставки его в электронное письмо. Я хотел бы пропустить копирование пустых ячеек и вставить только те ячейки, которые содержат данные.

Диапазон должен оставаться прежним, поскольку это таблица, заполненная из внешних источников. Иногда ячейки могут быть пустыми, а иногда пустыми будут разные ячейки. Иногда ни одна ячейка не будет пуста.

Я пробовал константы. Тогда будет вставлен только диапазон C13:J13. Это единственная строка, в ячейках которой нет формул, только текст. Все остальные ячейки в диапазоне содержат формулы. Я думаю, было бы лучше проверить, <1 ли длина, а затем пропустить.

Sub PrepareMailOffer()
    Dim rng As Range
    Dim OutApp As Object
    Dim OutMail As Object

    Set rng = Nothing
    On Error Resume Next

    Set rng = Sheets("000000").Range("C12:J29").SpecialCells(xlCellTypeVisible)
    On Error GoTo 0

    If rng Is Nothing Then
        MsgBox "The selection is not a range or the sheet is protected" & _
               vbNewLine & "please correct and try again.", vbOKOnly
        Exit Sub
    End If

    With Application
        .EnableEvents = False
        .ScreenUpdating = False
    End With

    Set OutApp = CreateObject("Outlook.Application")
    Set OutMail = OutApp.CreateItem(0)

    On Error Resume Next
    With OutMail
        .To = Range("N4").Value
        .CC = ""
        .BCC = ""
        .Subject = ""
        .HTMLBody = "" & _
            RangetoHTML(rng) & _
            "" & _
        .Display
    End With
    On Error GoTo 0

    With Application
        .EnableEvents = True
        .ScreenUpdating = True
    End With

    Set OutMail = Nothing
    Set OutApp = Nothing
End Sub

Function RangetoHTML(rng As Range)
    Dim fso As Object
    Dim ts As Object
    Dim TempFile As String
    Dim TempWB As Workbook

    TempFile = Environ$("temp") & "\" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm"

    'Copy the range and create a new workbook to paste the data in
    rng.Copy
    Set TempWB = Workbooks.Add(1)
    With TempWB.Sheets(1)
        .Cells(1).PasteSpecial Paste:=8
        .Cells(1).PasteSpecial xlPasteValues, , False, False
        .Cells(1).PasteSpecial xlPasteFormats, , False, False
        .Cells(1).Select
        Application.CutCopyMode = False
        On Error Resume Next
        .DrawingObjects.Visible = True
        .DrawingObjects.Delete
        On Error GoTo 0
    End With

    'Publish the sheet to a htm file
    With TempWB.PublishObjects.Add( _
         SourceType:=xlSourceRange, _
         Filename:=TempFile, _
         Sheet:=TempWB.Sheets(1).Name, _
         Source:=TempWB.Sheets(1).UsedRange.Address, _
         HtmlType:=xlHtmlStatic)
        .Publish (True)
    End With

    'Read all data from the htm file into RangetoHTML
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2)
    RangetoHTML = ts.readall
    ts.Close
    RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource = ", _
                          "align=left x:publishsource = ")

    'Close TempWB
    TempWB.Close savechanges:=False

    'Delete the htm file we used in this function
    Kill TempFile

    Set ts = Nothing
    Set fso = Nothing
    Set TempWB = Nothing
End Function

Код работает, когда у меня нет пустых ячеек.

Отфильтрован ли диапазон, который вы пытаетесь обработать, для использования xlCellTypeVisible? Я имею в виду, есть ли скрытые строки? И есть ли пустые ячейки или пустые строки? Если вы хотите пропустить пустые ячейки, как бы вы хотели, чтобы код вел себя в случае таких ячеек? Должны ли столбцы перемещаться вместо пустых ячеек? Вы понимаете, что я имею в виду? Я думаю, было бы хорошо поместить изображение с существующими (содержащими пустые ячейки) и изображение, показывающее, как выглядит обработанный диапазон...

FaneDuru 26.07.2024 15:28

В моем первоначальном проекте предполагалась фильтрация, но вместо этого я решил использовать формулы. Я не обновлял код, чтобы отразить это изменение. Нет скрытых строк, есть целые пустые строки. Я хочу, чтобы код выбирал и вставлял только строки с данными и пропускал пустые строки.

kyle245 29.07.2024 07:38

Я забыл упомянуть, что «пустые строки» содержат формулы, поэтому технически они не пустые. Вот почему я думаю, что проверка длины будет лучшим решением, чем SkipBlanks, который не работает.

kyle245 29.07.2024 08:45

Итак, вы не хотите пропускать пустые ячейки, что выглядело бы странно, остальные столбцы/строки должны скользить в одном направлении. Затем есть пустые строки, а также результаты формул. Это означает, что xlCellTypeVisible бесполезен, и вы также не можете использовать xlCellTypeConstants для получения прерывистого диапазона, пропуская пустые строки. Но функция рабочего листа CountBlank должна работать, и вы можете скрыть пустые строки, а затем использовать xlCellTypeVisible. Вы копируете диапазон **вручную? Вам нужно снова сделать скрытую строку видимой после копирования диапазона?

FaneDuru 29.07.2024 09:58

Вероятно, вам нужно показать остальную часть кода, чтобы увидеть, как вы копируете диапазон...

FaneDuru 29.07.2024 10:03

Я отредактировал свой вопрос, включив полный код

kyle245 29.07.2024 10:26
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
1
6
88
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ссылка на непустые строки

Sub ReferenceNonBlankRows()
    
    ' Define constants.
    Const SHEET_NAME As String = "000000"
    Const RANGE_ADDRESS As String = "C12:J29"
    
    ' Reference the main objects.
    Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
    Dim ws As Worksheet: Set ws = wb.Worksheets(SHEET_NAME)
    Dim rg As Range: Set rg = ws.Range(RANGE_ADDRESS)
    
    ' Store the range's number of columns in a variable ('ColumnsCount').
    Dim ColumnsCount As Long: ColumnsCount = rg.Columns.Count
    
    ' Declare additional variables.
    Dim urg As Range, rrg As Range, IsFoundNonBlankRow As Boolean
    
    ' Loop through the rows ('rrg') of the range ('rg')
    ' and combine each non-blank row ('rrg') into a unioned range ('urg').
    For Each rrg In rg.Rows
        ' 'CountBlank' counts the number of blank cells
        ' (cells whose length is 0) in a range.
        If Application.CountBlank(rrg) < ColumnsCount Then
            If IsFoundNonBlankRow Then
                Set urg = Union(urg, rrg)
            Else
                Set urg = rrg
                IsFoundNonBlankRow = True ' never reset
            End If
        End If
    Next rrg
    
    ' Check if all rows are blank.
    If Not IsFoundNonBlankRow Then
        MsgBox "All rows in the range ""'" & ws.Name & "'!" _
            & rg.Address(0, 0) & """ are blank!", vbExclamation
        Exit Sub
    End If
    
    ' Continue using 'urg', e.g.:
    MsgBox "The rows ""'" & ws.Name & "'!" _
        & urg.Address(0, 0) & """ are not blank.", vbInformation
        
End Sub

РЕДАКТИРОВАТЬ

  • Вы можете создать функцию, используя приведенную выше идею.
Function RefNonBlankRows( _
    ByVal rg As Range, _
    Optional ByVal ShowFailMessage As Boolean = False) _
As Range
    
    ' Store the range's number of columns in a variable ('ColumnsCount').
    Dim ColumnsCount As Long: ColumnsCount = rg.Columns.Count
    
    ' Declare additional variables.
    Dim urg As Range, rrg As Range, IsFoundNonBlankRow As Boolean
    
    ' Loop through the rows ('rrg') of the range ('rg')
    ' and combine each non-blank row ('rrg') into a unioned range ('urg').
    For Each rrg In rg.Rows
        ' 'CountBlank' counts the number of blank cells
        ' (cells whose length is 0) in a range.
        If Application.CountBlank(rrg) < ColumnsCount Then
            If IsFoundNonBlankRow Then
                Set urg = Union(urg, rrg)
            Else
                Set urg = rrg
                IsFoundNonBlankRow = True ' never reset
            End If
        End If
    Next rrg
    
    ' Check if all rows are blank.
    If Not IsFoundNonBlankRow Then
        If ShowFailMessage Then
            MsgBox "All rows in the range ""'" & rg.Worksheet.Name & "'!" _
                & rg.Address(0, 0) & """ are blank!", vbExclamation
        End If
        Exit Function
    End If
    
    ' Assign non-blank rows to the result of the function.
    Set RefNonBlankRows = urg

End Function
  • Тогда вы можете использовать его следующим образом.
Sub PrepareMailOffer()
    
    ' Define constants.
    Const SHEET_NAME As String = "000000"
    Const RANGE_ADDRESS As String = "C12:J29"
    Const EMAIL_CELL_ADDRESS As String = "N4"
    
    ' Reference the main objects.
    Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
    Dim ws As Worksheet: Set ws = wb.Worksheets(SHEET_NAME)
    Dim rg As Range: Set rg = ws.Range(RANGE_ADDRESS)

    ' Reference the non-blank rows.
    Dim nbrg As Range: Set nbrg = RefNonBlankRows(rg, True)
    If nbrg Is Nothing Then Exit Sub

    Dim outApp As Object: Set outApp = CreateObject("Outlook.Application")
    Dim outMail As Object: Set outMail = OutApp.CreateItem(0)
    
    With Application
        .ScreenUpdating = False
        .EnableEvents = False
    End With

    On Error Resume Next
        With outMail
            .To = ws.Range(EMAIL_CELL_ADDRESS).Value
            .CC = ""
            .BCC = ""
            .Subject = ""
            .HTMLBody = "" _
                & "" _
                & RangetoHTML(nbrg) _
                & ""
            .Display
        End With
    On Error GoTo 0

    With Application
        .EnableEvents = True
        .ScreenUpdating = True
    End With

End Sub

Огромное спасибо за это - все работает так, как я и предполагал. Мне жаль, что я не могу также пометить ваш ответ «зеленым», но FaneDuru работает так же хорошо, и они были первыми, кто помог мне в моем небольшом проекте. Заботиться!

kyle245 29.07.2024 15:07
Ответ принят как подходящий

Пожалуйста, попробуйте следующий адаптированный код, который скрывает пустые строки (даже с пробелами в формуле) и обрабатывает видимые ячейки результирующего диапазона:

Sub PrepareMailOffer()
    Dim ws As Worksheet, rng As Range, rngH As Range, i As Long
    Dim OutApp As Object, OutMail As Object

    Set ws = Sheets("000000")
    Set rng = ws.Range("C12:J29")

    'place the blank rows in a Union range and hide them, at once:
    For i = 1 To rng.rows.count
       If WorksheetFunction.CountBlank(rng.rows(i)) = rng.Columns.count Then
           addToRange rngH, rng.rows(i).EntireRow
       End If
    Next i
    If Not rngH Is Nothing Then rngH.EntireRow.Hidden = True 'hide the blank rows
    
    With Application
        .EnableEvents = False
        .ScreenUpdating = False
    End With

    Set OutApp = CreateObject("Outlook.Application")
    Set OutMail = OutApp.CreateItem(0)


    With OutMail
        .To = Range("N4").Value
        .cc = ""
        .BCC = ""
        .Subject = ""
        .HTMLBody = "" & _
            RangetoHTML(rng.SpecialCells(xlCellTypeVisible)) & _
            "" & _
        .Display
    End With
    
    If Not rngH Is Nothing Then rngH.EntireRow.Hidden = False 'unhide the previous hidden rows
    
    With Application
        .EnableEvents = True
        .ScreenUpdating = True
    End With

    Set OutMail = Nothing
    Set OutApp = Nothing
End Sub

Sub addToRange(rngU As Range, rng As Range)
    If rngU Is Nothing Then
        Set rngU = rng
    Else
        Set rngU = Union(rngU, rng)
    End If
End Sub

On Error Resume Next только в контексте вашего кода не сообщайте вам, какая у вас ошибка, если таковая имеется...

Вам следует использовать ту же (существующую) функцию RangetoHTML...

Пожалуйста, оставьте отзыв после тестирования.

Я отредактировал свой вопрос, включив полный код

kyle245 29.07.2024 10:26

Огромное спасибо за это - все работает так, как я хотел.

kyle245 29.07.2024 15:08

Другие вопросы по теме