为什么在添加VBA时,我的条件格式偏移?

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

如果expression式=($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在debugging时提供了正确的行,但是我添加的条件公式似乎是一行或多行 – 取决于我设置行的解决scheme。 所以我结束了一个条件格式,它有一个行应该已经格式化的偏移量。

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

设置行必须是dynamic的,因为这是用来在不同的工作表上设置条件格式的,它们的数据可以从不同的行开始。

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

编辑:更具体地说,这不是一个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<>"") ,那么一切正常。

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

编辑: 其他任务信息

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

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

为了保持最小值,我使用NamedRanges来确定正确的偏移量并确定正确的DefaultProgessColumn

GetTitleRow用于通过NamedRange或标题内容来确定标题行。

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

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

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

strMatchCol1 – 是范围的名称。

明白了,哈哈 设置ActiveCell之前做咕噜工作…

 ActiveSheet.Range("A1").Activate 

当添加FromatCondition时,Excel正在调整它的自动调整范围。

条件格式和数据validation显示这种奇怪的行为的原因是因为他们使用的公式是在正常的计算链之外。 他们必须是这样的,你可以参考公式中的活动单元格。 如果你在G1中,你不能input=G1=""因为你会创build一个循环引用。 但是在CF或DV中,您可以键入该公式。 这些公式与当前单元格不相关,不像真正的公式。

当你input一个CF公式时,它总是相对于活动单元格。 如果在CF中,你做了一个公式

 =ISBLANK($G2) 

而你在A5中,Excel将其转换为

 =ISBLANK(R[-3]C7) 

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

 =ISBLANK($G655536) 

(用于Excel 2003)。 它偏移-3行,并包装到电子表格的底部。

您可以使用Application.ConvertFormula使公式相对于其他单元格。 如果我在第5行,我的范围的开始是在第2行,我相对于第8行公式。这样R [-3]将公式放在A5作为$ G5(从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) row-wise,因为在这个例子中列是绝对的。 如果在CF公式中行和列都是相对的,则需要更多的抵消。 此外,这只有在活动单元格低于您的范围中的第一个单元格时才有效。 为了使其更通用,您将必须确定活动单元相对于范围和偏移的位置。 如果偏移量使您位于第1行上方,则需要对其进行编码,以便将它引用到Excel版本的总行数底部附近的单元格。

如果你认为select有点混乱,我相信你会同意这是更糟的。 即使我憎恶不必要的select和激活,条件格式和数据validation是两个地方,这是一个必要的邪恶。

一个简单的例子:

 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 

关于我在其他答覆中所提出的意见:

如果你必须为许多行执行这个操作,将整个范围加载到内存(一个数组)中并检查数组内的条件肯定会更快,然后在那些需要写入的单元格上进行写操作(格式化)。
我可以同意,在这种情况下,这种技术不是“必要的”,但是这是一个很好的做法,因为它对于之后的许多(任何types)定制都很灵活,并且更容易debugging(使用immediate / locals / watch窗口)。
我并不喜欢Offset,尽pipe我没有说它不是应该的,在一些有限的情况下,我可以说问题的可能性“可能”很小:我经历过一些商业用户倾向于使用它不断(这里偏移+3,有偏移-3,然后再-2等等); 虽然写起来很容易,但我可以告诉你这是修改的地狱。 当最终用户进行更改时,也经常遇到错误。
我非常喜欢使用头文件(尽pipe我也是减lessExcel数据库function的粉丝,因为对于很多人来说,它避免了访问),因为它可以让你非常灵活。 即使当我使用第1和第2列, 更好的办法是根据头部命名范围的位置dynamic检索列nr。 如果插入另一列,则不会出现错误。

最后但并非最不重要的一点,这听起来有些夸张,但是最后一次,我使用了一个带有属性和函数的类模块来dynamic地执行每个工作表中的潜在数据的所有检索,对所有我能想到的错误以及一些额外的函数进行检查执行特定的任务。
因此,如果您需要来自特定工作表的多种types的数据,则可以实例化该类,并使用所定义的function访问所有数据。 到目前为止,我还没有注意到任何人的这种做法,但是尽pipe工作多一点,但是它却给你带来了一些麻烦(你可以反复使用相同的原则)。
现在我不认为这是你所需要的; 但是可能有一天你需要为那些不知道工作原理的terminal用户制作大型工具,但由于他们可能自己做了些什么(即使不是你的“错误”),他们会抱怨很多事情。 记住这一点很好。