Delphi 到 Excel - 使用自动过滤器删除未知数据元素
Delphi to Excel - Using Autofilter to delete unknown data elements
Delphi 东京,Excel 2016。通过使用 Delphi 程序,我控制了 Excel。我试图删除单个 sheet 中的所有行,除了在特定列中具有特定值的行...例如,我有一个企业列表,其中第 3 列是企业的城市。我需要删除除 City in ('Chicago'、'Denver'、'Columbus') 以外的所有行。我已经构建并查看了一个 Excel 宏,以了解 Excel 是如何做到的……具体来说,它会打开 AutoFilter,选择除这些城市之外的所有值,然后删除。我的问题是……我如何知道此列中的值……?
这是VBA宏代码...
Selection.AutoFilter
ActiveSheet.Range("$A:$AF").AutoFilter Field:=3, Criteria1:=Array( _
"ADDISON", "CARROLLTON", "DALLAS", "DANBURY", "EDEN PRAIRIE", "EL PASO", "ELDRIDGE", _
"FARMERS BRANCH", "Franklin", "GEISMAR", "GRAPEVINE", "HOUSTON", "KROTZ SPRINGS", _
"MASON CITY", "NEW BRAUNFELS", "PALO ALTO", "PLANO", "POWAY", "PURCHASE", _
"RICHARDSON", "SAINT PAUL", "SAN ANTONIO", "SOUTHLAKE", "SUNNYVALE", "THE WOODLANDS" _
, "ULYSSES", "WEST LAKE HLS"), Operator:=xlFilterValues
Rows("2:62").Select
Selection.Delete Shift:=xlUp
ActiveSheet.ShowAllData
我需要做的是构建一个包含所有城市的数组,除了我要删除的城市。 AutoFilter 知道所有唯一值是什么...除了遍历所有行之外,我如何读取 Autofilter(也称为唯一值列表)?
The AutoFilter knows what all unique values are... How do I read the Autofilter
我认为您无法从自动筛选中读取唯一值。如果您查看 filter 的定义属性,唯一值不在其中,只有过滤器运行的单元格范围。
可能最接近的方法是确定过滤范围内的哪些行显示在屏幕上,然后删除未显示的行。 This code 展示了如何确定哪些行被隐藏。但这对我来说似乎 "around the houses" 并且在任何情况下都不是你特别要求的。
因此,您将不得不以某种方式自己迭代范围。
What I need to do is to build an array of ALL cities EXCEPT the ones I want to delete.
如果忽略 Excel AutoFilter,这实际上 far 在 Delphi 代码中更容易做到,因为找到唯一的单元格值几乎是微不足道的在 Excel 范围内使用 Delphi 代码。
下面,我将展示如何计算 Delphi 等同于 this answer 中的 Coderre 公式。随你喜欢。
开始一个新的 Delphi VCL 项目并将 TCheckListBox 拖放到它上面。然后编译和
执行下面的代码。该代码使用 A、B 和 C 等值填充 Excel 范围
然后提取唯一值并用它们填充 ChecklistBox。在那之后,
您可以使用各个复选框的状态来处理 Excel 范围
随心所欲。
vExcel,
vWorkBook,
vSheet,
vRange : OleVariant;
procedure GetUniqueValues(vRange : OleVariant; Strings : TStrings);
// scans the Excel range represented by vRange and populates the Strings
// variable with the unique values for in the range's Cells
var
S : String;
Row,
Col : Integer;
begin
Strings.BeginUpdate;
Strings.Clear;
try
for Row := 2 to vRange.Rows.Count do begin
for Col := 1 to vRange.Columns.Count do begin
S := vRange.Cells[Row, Col].Value;
if Strings.IndexOf(S) < 0 then
Strings.Add(S);
end;
end;
finally
Strings.EndUpdate;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
i : Integer;
begin
vExcel := CreateOleObject('Excel.Application');
vExcel.Visible := True;
// Create a new workbox and populate two columns in it with random
// character data
vWorkBook := vExcel.WorkBooks.Add;
vSheet := vWorkBook.ActiveSheet;
vSheet.Range['A1'].Value := 'City';
for i := 1 to 20 do begin
vSheet.Range['A' + IntToStr(1 + i)].Value := Chr(Random(3) + Ord('A'));
vSheet.Range['B' + IntToStr(1 + i)].Value := Chr(Random(4) + Ord('A'));
end;
// Extract the range A2..B21
vRange := vSheet.Range['A2', 'B21'];
// Set CheckListBox1 to sort its contents
CheckListBox1.Sorted := True;
// Now get the unique values
GetUniqueValues(vRange, CheckListBox1.Items);
// Do whatever you like with tthe results
for i := 0 to CheckListBox1.Items.Count - 1 do begin
if not (CheckListBox1.State[i] = cbChecked) then
;
end;
end;
顺便说一句,如果您查看 Excel 的自动化对象的导入单元之一,例如Excel2000.Pas,您会看到其中定义了 IAutoFilter 的接口,因此如果您确实需要,可以从 Delphi 代码访问它。
此外,如果我自己这样做,我可能会通过使用像 TAdoQuery 这样的 ADO 对象访问电子表格来在 SQL 中进行数据操作,因为像 "delete all rows where some column value is not in a list of values" 这样的操作非常重要对于那种治疗。
如您所知,AutoFilter
不提供唯一值,模仿您试图实现的手动过滤设置的功能会变得相当复杂。
我的建议是使用 Range.AdvancedFilter
而不是 Range.AutoFilter
。它有一种更简单的方法来定义过滤条件。
您将从 Delphi 调用的宏如下所示:
Public Sub UseAdvancedFilter()
Dim MyRange As Range
Set MyRange = Range("A1").CurrentRegion
Range(MyRange.Address).AdvancedFilter _
Action:=xlFilterInPlace, _
CriteriaRange:=Range("A28:C29")
Rows("2:" & MyRange.Rows.Count).Select
Selection.Delete Shift:=xlUp
ActiveSheet.ShowAllData
End Sub
这与您在 MyRange
中的数据和您在 CriteriaRange
中的标准一致。
(我使用拆分视图来缩小图像尺寸。4 到 19 之间的所有行都有数据)
您还有更多列,但我们可以演示文件管理器如何处理这三列。数据范围 (MyRange
) 必须包含数据的标题。 City 字段的标题 City
与 CriteriaRange
.
的标题匹配
CriteriaRange
很有趣。我们有三个标题单元格,都带有 City
字段名称。然后我们有三个条件:<>Denver
、<>Chicago
和 <>Dallas
。同一行的条件,它们之间形成一个逻辑AND
函数,<>
当然意味着not equal to
。因此,选择标准变为 select records where City is not Denver and City is not Chicago and City is not Dallas
.
结果与您的手动 AutoFilter
测试非常相似。
如果Public UseAdvancedFilter
过程放在public模块中,可以直接从Delphi中调用,如:
Excel.Run('UseAdvancedFilter');
前提是安全设置不禁止它。
上述解决方案遵循您删除所有不需要的数据行的想法。如果你真的不想/不需要删除不需要的数据,而是隐藏它,为了复制想要的数据,你可以按如下方式更改上面的内容:
将条件范围更改为
City
Denver
Chicago
Dallas
是的,那只是一栏。不同行上的条件,在它们之间形成一个逻辑 OR
函数。因此选择变成
`select records where City is Denver OR City is Chicago OR City is Dallas`.
然后,我们需要更改宏对选择的操作,f.ex。
'Selection.Delete Shift:=xlUp
Selection.Copy Destination:=Range("A40")
这会将所选记录复制到目标以供进一步处理。
Delphi 东京,Excel 2016。通过使用 Delphi 程序,我控制了 Excel。我试图删除单个 sheet 中的所有行,除了在特定列中具有特定值的行...例如,我有一个企业列表,其中第 3 列是企业的城市。我需要删除除 City in ('Chicago'、'Denver'、'Columbus') 以外的所有行。我已经构建并查看了一个 Excel 宏,以了解 Excel 是如何做到的……具体来说,它会打开 AutoFilter,选择除这些城市之外的所有值,然后删除。我的问题是……我如何知道此列中的值……?
这是VBA宏代码...
Selection.AutoFilter
ActiveSheet.Range("$A:$AF").AutoFilter Field:=3, Criteria1:=Array( _
"ADDISON", "CARROLLTON", "DALLAS", "DANBURY", "EDEN PRAIRIE", "EL PASO", "ELDRIDGE", _
"FARMERS BRANCH", "Franklin", "GEISMAR", "GRAPEVINE", "HOUSTON", "KROTZ SPRINGS", _
"MASON CITY", "NEW BRAUNFELS", "PALO ALTO", "PLANO", "POWAY", "PURCHASE", _
"RICHARDSON", "SAINT PAUL", "SAN ANTONIO", "SOUTHLAKE", "SUNNYVALE", "THE WOODLANDS" _
, "ULYSSES", "WEST LAKE HLS"), Operator:=xlFilterValues
Rows("2:62").Select
Selection.Delete Shift:=xlUp
ActiveSheet.ShowAllData
我需要做的是构建一个包含所有城市的数组,除了我要删除的城市。 AutoFilter 知道所有唯一值是什么...除了遍历所有行之外,我如何读取 Autofilter(也称为唯一值列表)?
The AutoFilter knows what all unique values are... How do I read the Autofilter
我认为您无法从自动筛选中读取唯一值。如果您查看 filter 的定义属性,唯一值不在其中,只有过滤器运行的单元格范围。
可能最接近的方法是确定过滤范围内的哪些行显示在屏幕上,然后删除未显示的行。 This code 展示了如何确定哪些行被隐藏。但这对我来说似乎 "around the houses" 并且在任何情况下都不是你特别要求的。
因此,您将不得不以某种方式自己迭代范围。
What I need to do is to build an array of ALL cities EXCEPT the ones I want to delete.
如果忽略 Excel AutoFilter,这实际上 far 在 Delphi 代码中更容易做到,因为找到唯一的单元格值几乎是微不足道的在 Excel 范围内使用 Delphi 代码。
下面,我将展示如何计算 Delphi 等同于 this answer 中的 Coderre 公式。随你喜欢。
开始一个新的 Delphi VCL 项目并将 TCheckListBox 拖放到它上面。然后编译和 执行下面的代码。该代码使用 A、B 和 C 等值填充 Excel 范围 然后提取唯一值并用它们填充 ChecklistBox。在那之后, 您可以使用各个复选框的状态来处理 Excel 范围 随心所欲。
vExcel,
vWorkBook,
vSheet,
vRange : OleVariant;
procedure GetUniqueValues(vRange : OleVariant; Strings : TStrings);
// scans the Excel range represented by vRange and populates the Strings
// variable with the unique values for in the range's Cells
var
S : String;
Row,
Col : Integer;
begin
Strings.BeginUpdate;
Strings.Clear;
try
for Row := 2 to vRange.Rows.Count do begin
for Col := 1 to vRange.Columns.Count do begin
S := vRange.Cells[Row, Col].Value;
if Strings.IndexOf(S) < 0 then
Strings.Add(S);
end;
end;
finally
Strings.EndUpdate;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
i : Integer;
begin
vExcel := CreateOleObject('Excel.Application');
vExcel.Visible := True;
// Create a new workbox and populate two columns in it with random
// character data
vWorkBook := vExcel.WorkBooks.Add;
vSheet := vWorkBook.ActiveSheet;
vSheet.Range['A1'].Value := 'City';
for i := 1 to 20 do begin
vSheet.Range['A' + IntToStr(1 + i)].Value := Chr(Random(3) + Ord('A'));
vSheet.Range['B' + IntToStr(1 + i)].Value := Chr(Random(4) + Ord('A'));
end;
// Extract the range A2..B21
vRange := vSheet.Range['A2', 'B21'];
// Set CheckListBox1 to sort its contents
CheckListBox1.Sorted := True;
// Now get the unique values
GetUniqueValues(vRange, CheckListBox1.Items);
// Do whatever you like with tthe results
for i := 0 to CheckListBox1.Items.Count - 1 do begin
if not (CheckListBox1.State[i] = cbChecked) then
;
end;
end;
顺便说一句,如果您查看 Excel 的自动化对象的导入单元之一,例如Excel2000.Pas,您会看到其中定义了 IAutoFilter 的接口,因此如果您确实需要,可以从 Delphi 代码访问它。
此外,如果我自己这样做,我可能会通过使用像 TAdoQuery 这样的 ADO 对象访问电子表格来在 SQL 中进行数据操作,因为像 "delete all rows where some column value is not in a list of values" 这样的操作非常重要对于那种治疗。
如您所知,AutoFilter
不提供唯一值,模仿您试图实现的手动过滤设置的功能会变得相当复杂。
我的建议是使用 Range.AdvancedFilter
而不是 Range.AutoFilter
。它有一种更简单的方法来定义过滤条件。
您将从 Delphi 调用的宏如下所示:
Public Sub UseAdvancedFilter()
Dim MyRange As Range
Set MyRange = Range("A1").CurrentRegion
Range(MyRange.Address).AdvancedFilter _
Action:=xlFilterInPlace, _
CriteriaRange:=Range("A28:C29")
Rows("2:" & MyRange.Rows.Count).Select
Selection.Delete Shift:=xlUp
ActiveSheet.ShowAllData
End Sub
这与您在 MyRange
中的数据和您在 CriteriaRange
中的标准一致。
(我使用拆分视图来缩小图像尺寸。4 到 19 之间的所有行都有数据)
您还有更多列,但我们可以演示文件管理器如何处理这三列。数据范围 (MyRange
) 必须包含数据的标题。 City 字段的标题 City
与 CriteriaRange
.
CriteriaRange
很有趣。我们有三个标题单元格,都带有 City
字段名称。然后我们有三个条件:<>Denver
、<>Chicago
和 <>Dallas
。同一行的条件,它们之间形成一个逻辑AND
函数,<>
当然意味着not equal to
。因此,选择标准变为 select records where City is not Denver and City is not Chicago and City is not Dallas
.
结果与您的手动 AutoFilter
测试非常相似。
如果Public UseAdvancedFilter
过程放在public模块中,可以直接从Delphi中调用,如:
Excel.Run('UseAdvancedFilter');
前提是安全设置不禁止它。
上述解决方案遵循您删除所有不需要的数据行的想法。如果你真的不想/不需要删除不需要的数据,而是隐藏它,为了复制想要的数据,你可以按如下方式更改上面的内容:
将条件范围更改为
City
Denver
Chicago
Dallas
是的,那只是一栏。不同行上的条件,在它们之间形成一个逻辑 OR
函数。因此选择变成
`select records where City is Denver OR City is Chicago OR City is Dallas`.
然后,我们需要更改宏对选择的操作,f.ex。
'Selection.Delete Shift:=xlUp
Selection.Copy Destination:=Range("A40")
这会将所选记录复制到目标以供进一步处理。