3

我试图添加这样的条件格式:

如果表达式=($G5<>"")然后将设置内部设置为绿色,则将其用于 $A$5:$H$25。

试过这个,工作正常,正如预期的那样,然后尝试使用以下代码将其调整为 VBA 代码,这是有效的,但不符合预期:

With ActiveSheet.UsedRange.Offset(1)
  .FormatConditions.Delete
  'set used row range to green interior color, if "Erledigt Datum" is not empty
  With .FormatConditions.Add(Type:=xlExpression, _
                             Formula1:="=($" & cstrDefaultProgressColumn & _
                                                      .row & "<>"""")")
        .Interior.ColorIndex = 4
      End With
End With

问题是.row在调试时提供了正确的行,但是我添加的条件公式似乎关闭了一行或多行-取决于我设置行的解决方案。所以我最终得到了一个条件格式,它对行有一个偏移量,应该已经被格式化了。

在对话框中它是=($G6<>"")G3 或 G100310 或类似的东西。但不是我想要的 G5。

设置行必须是动态的,因为这用于在不同的工作表上设置条件格式,这些工作表的数据可以从不同的行开始。

我怀疑我的With安排,但它并没有解决这个问题。

编辑:更具体地说,这不是UsedRange 问题,也有同样的问题:

Dim rngData As Range
Set rngData = ActiveSheet.Range("A:H") 'ActiveSheet.UsedRange.Offset(1)

rngData.FormatConditions.Delete

With rngData.FormatConditions.Add(Type:=xlExpression, _
                                  Formula1:="=($" & cstrDefaultProgressColumn & _
                                                  1 & "<>"""")")
    .Interior.ColorIndex = 4
End With

我的数据如下所示:

1 -> empty cells
2 -> empty cells
3 -> empty cells
4 -> TitleCols -> A;B;C;...;H
5 -> Data to TitleCols
. .
. .
. .
25

当我在 Excel 2007 上执行此编辑后的代码并在条件对话框中查找公式时,它是=($G1048571<>"")- 它应该是=($G1<>""),然后一切正常。

更奇怪的是 - 这是一个工作良好的代码的编辑版本,用于为每一行添加条件格式。但后来我意识到,可以编写一个表达式,格式化整行或其中的一部分 - 以为这会在一分钟内适应,现在这个^^

编辑: 附加任务信息

我在这里使用条件格式,因为这个函数应该设置一个表格来对用户输入做出反应。因此,如果正确设置并且用户编辑了此表的条件化列中的某些单元格,则相应行将变为绿色,用于使用的行范围。

现在,因为在主标题行之前可能有行,并且可能有不同数量的数据列,而且目标列可能会改变,所以我当然会使用一些特定的信息。

为了使它们最小化,我确实使用 NamedRanges 来确定正确的偏移量并确定正确的DefaultProgessColumn.

GetTitleRow用于通过 NamedRange 或 header-contents 确定 header-row。

With ActiveSheet.UsedRange.Offset(GetTitleRow(ActiveSheet.UsedRange) - _
                                ActiveSheet.UsedRange.Rows(1).row + 1)

更正了我的公式 1,因为我发现之前的构造没有很好地形成。

Formula1:="=(" & Cells(.row, _
           Range(strMatchCol1).Column).Address(RowAbsolute:=False) & _
           "<>"""")"

strMatchCol1- 是范围的名称。

4

3 回答 3

4

明白了,呵呵。在进行繁重的工作之前设置 ActiveCell ...

ActiveSheet.Range("A1").Activate

Excel 正在拉动它的自动范围调整,当添加 FromatCondition 时,它会抛出公式。

于 2012-09-14T10:00:24.900 回答
4

条件格式和数据验证表现出这种奇怪行为的原因是因为它们使用的公式超出了正常的计算链。它们必须是这样,您才能在公式中引用活动单元格。如果您在 G1 中,则无法键入=G1="",因为您将创建循环引用。但在 CF 或 DV 中,您可以键入该公式。与实际公式不同,这些公式与当前单元格无关。

当您输入 CF 公式时,它始终与活动单元格相关。如果,在 CF 中,你制定了一个公式

=ISBLANK($G2)

你在 A5 中,Excel 将其转换为

=ISBLANK(R[-3]C7)

当它被放入 CF 时,它最终与它所应用的单元格相关。所以在第2行,公式出来

=ISBLANK($G655536)

(对于 Excel 2003)。它偏移 -3 行,并环绕到电子表格的底部。

您可以使用 Application.ConvertFormula 使公式相对于其他单元格。如果我在第 5 行并且我的范围的开始在第 2 行,我将公式相对于第 8 行。这样,R[-3] 会将公式作为 $G5 放入 A5(从 A8 向上三行)。

Sub test()

    Dim cstrDefaultProgressColumn As String
    Dim sFormula As String

    cstrDefaultProgressColumn = "$G"

    With ActiveSheet.UsedRange.Offset(1)
        .FormatConditions.Delete
        'set used row range to green interior color, if "Erledigt Datum" is not empty

        'Build formula
        sFormula = "=ISBLANK(" & cstrDefaultProgressColumn & .Row & ")"

        'convert to r1c1
        sFormula = Application.ConvertFormula(sFormula, xlA1, xlR1C1)

        'convert to a1 and make relative
        sFormula = Application.ConvertFormula(sFormula, xlR1C1, xlA1, , ActiveCell.Offset(ActiveCell.Row - .Cells(1).Row))

        With .FormatConditions.Add(Type:=xlExpression, _
                                 Formula1:=sFormula)

            .Interior.ColorIndex = 4
        End With

    End With

End Sub

我只按行偏移.Cells(1),因为在此示例中该列是绝对的。如果 CF 公式中的行和列都是相对的,则需要更多的偏移量。此外,这仅在活动单元格低于您范围内的第一个单元格时才有效。为了使其更通用,您必须确定活动单元格相对于范围的位置并适当地偏移。如果偏移量使您高于第 1 行,则您需要对其进行编码,以便它引用更接近您的 Excel 版本的总行数底部的单元格。

如果你认为选择有点麻烦,我相信你会同意这更糟。尽管我讨厌不必要的选择和激活,但条件格式和数据验证是必要的两个地方。

于 2012-09-14T13:35:06.413 回答
1

一个简单的例子:

Sub Format_Range()

Dim oRange          As Range
Dim iRange_Rows     As Integer
Dim iCnt            As Integer


'First, create a named range manually in Excel (eg. "FORMAT_RANGE")
'In your case that would be range "$A$5:$H$25". 
'You only need to do this once, 
'through VBA you can afterwards dynamically adapt size + location at any time. 

'If you don't feel comfortable with that, you can create headers 
'and look for the headers dynamically in the sheet to retrieve 
'their position dynamically too. 

'Setting this range makes it independent
'from which sheet in the workbook is active
'No unnecessary .Activate is needed and certainly no hard coded "A1" cell. 
'(which makes it more potentially subject to bugs later on) 
Set oRange = ThisWorkbook.Names("FORMAT_RANGE").RefersToRange
iRange_Rows = oRange.Rows.Count

For iCnt = 1 To iRange_Rows
    If oRange(iCnt, 1) <> oRange(iCnt, 2) Then
        oRange(iCnt, 2).Interior.ColorIndex = 4
    End If
Next iCnt

End Sub

关于我对另一个回复的评论:

如果您必须对多行执行此操作,则将整个范围加载到内存(数组)并检查数组中的条件肯定会更快,然后在需要写入的那些单元格上进行写入(格式化)。
我可以同意这种技术在这种情况下不是“必要的” - 但是这是一种很好的做法,因为它对于之后的许多(任何类型的)自定义都是灵活的并且更容易调试(使用即时/本地/监视窗口)。
我不是 Offset 的粉丝,尽管我没有说它不能正常工作,在某些有限的情况下,我可以说出现问题的机会“可能”很小:我经历过一些商业用户倾向于使用它不断地(这里偏移+3,那里偏移-3,然后再-2,等等......);虽然写起来很容易,但我可以告诉你,修改是地狱。当最终用户进行更改时,它也经常受到错误的影响。
我非常“赞成”使用标题(尽管我也喜欢减少 Excel 的数据库功能,因为对于许多人来说,这会导致避免访问),因为它会给您带来很大的灵活性。即使我使用了第 1 列和第 2 列;更好的是根据标题的命名范围的位置动态检索列 nr。如果然后插入另一列,则不会出现错误。

最后但并非最不重要的一点,这听起来可能有些夸张,但最后一次,我使用了一个具有属性和函数的类模块来动态地执行对每张表中潜在数据的所有检索,对我能想到的所有错误和一些附加功能进行检查执行特定任务。
因此,如果您需要来自特定工作表的多种类型的数据,您可以实例化该类并让所有数据可供您使用,并可通过定义的函数访问。到目前为止,我还没有注意到有人这样做,但是尽管需要做更多的工作,但它给您带来的麻烦很少(您可以一遍又一遍地使用相同的原则)。
现在我认为这不是您所需要的;但是有一天,您可能需要为不知道它是如何工作的最终用户制作大型工具,但会因为他们可能自己做过的事情而抱怨很多事情(即使这不是您的“错”);记住这一点很好。

于 2012-09-14T12:47:40.860 回答