【问题标题】:Apply multiple filters from multiple comboboxes从多个组合框中应用多个过滤器
【发布时间】:2021-01-31 23:56:49
【问题描述】:

我有一个 adotable,我想从多个组合框应用多个过滤器,每个组合框都将一个过滤器应用于该表。我的问题是,每当我从组合框 1 中选择一个项目时,它都会应用其过滤器,但是当我从下一个组合框(组合框 2)中选择另一个项目时,它会删除前一个过滤器(组合框 1)并应用组合框 2 中的过滤器。我的问题是:如何使 adotable 保留来自 combobox1 或 combobox2 甚至两者的先前过滤器,但还添加来自 combobox3 的第三个过滤器以进行更深入的排序?提前致谢。 这就是我到目前为止所做的:

procedure TForm1.ComboBox1Change(Sender: TObject);
begin
ADOTable1.Filtered:=false;
ADOTable1.filter:='`enter code here`field1='+ QuotedStr(ComboBox1.Text);
ADOTable1.Filtered:=true;
end;

procedure TForm1.ComboBox2Change(Sender: TObject);
begin
ADOTable1.Filtered:=false;
ADOTable1.filter:=adotable1.Filter+'and field2='+ QuotedStr(ComboBox1.Text);
ADOTable1.Filtered:=true;
end;

procedure TForm1.ComboBox3Change(Sender: TObject);
begin
ADOTable1.Filtered:=false;
ADOTable1.filter:=adotable1.Filter+'and field3='+ QuotedStr(ComboBox1.Text);
ADOTable1.Filtered:=true;
end;

【问题讨论】:

    标签: delphi filter combobox pascal tadotable


    【解决方案1】:

    以上代码多次修改后报错,需要每次重新组合过滤文本

    procedure TForm1.ComboBox1Change(Sender: TObject);
    begin
        ComboBoxChange();
    end;
    
    procedure TForm1.ComboBox2Change(Sender: TObject);
    begin
        ComboBoxChange();
    end;
    
    procedure TForm1.ComboBox3Change(Sender: TObject);
    begin
        ComboBoxChange();
    end;
    
    
    procedure TForm1.ComboBoxChange();
    var
        count: integer;
        sFilter: string;
    begin
        count := 0;
        sFilter := '`enter code here`';
        
        if(ComboBox1.Text <> '') then
        begin
            sFilter := 'field1=' + ComboBox1.Text;
            Inc(count);
        end;
        if(ComboBox2.Text <> '')then
        begin
            if count > 0 then
                sFilter := sFilter + 'and field2=' + ComboBox2.Text
            else
                sFilter := sFilter + ' field2=' + ComboBox2.Text
            Inc(count);
        end;
        if(ComboBox3.Text <> '')then
        begin
            if count > 0 then
                sFilter := sFilter + 'and field3=' + ComboBox3.Text
            else
                sFilter := sFilter + ' field3=' + ComboBox3.Text
            Inc(count);
        end;
        ADOTable1.Filtered:=false;
            ADOTable1.filter:=sFilter;
        ADOTable1.Filtered:=true;
    end;
    

    【讨论】:

    • 您可以声明您的ComboBoxChange() 以匹配OnChange 事件的签名,并将其设置为对象检查器中“事件”选项卡中的每个组合框,以不创建3 个仅调用单个函数的单独事件处理程序。此外,最好将 sFilter 的值初始化为空字符串,以不创建任何过滤器并跳过进一步过滤,以防没有填充 ComboBox。
    【解决方案2】:

    免责声明:此答案中的解决方案需要 Generics 的支持,因此它不适用于旧版本的 Delphi (您不应该).

    1. 您可以应用Tag 属性来存储字段索引,您将使用该索引在过滤器生成中获取字段名称。

    2. 要存储每个过滤器的值,您可以使用 Form 的私有 TDictionary 字段。

      uses 
        { here all other modules }, System.Generics.Collections;
      
      type
        TForm1 = class(TForm)
          { here all components declaration }
        strict private
          Filters: TDictionary<Integer, string>;
      

      我们应该在 App 启动时初始化 Filters。您可以在执行初始设置的任何地方执行此操作(OnCreateOnShow 或表单的任何其他事件;initialization 部分等)。我将使用OnCreate 事件处理程序作为示例。您可以通过双击 OnCreate 附近的空单元格在 Object InspectorEvent 选项卡中生成空处理程序并将其自动附加到 Form:

      所以现在我们应该在这个事件处理程序中初始化Filters

      procedure TForm1.FormCreate(Sender: TObject);
      begin
        { here all your previous setup (if exist) }
        Filters := TDictionary<Integer, string>.Create;
      end;
      

      如果需要,您还应该在此处初始化过滤器的默认值。如果您在 Object Inspector 中设置 Text 的默认值并希望它们用于过滤查询,则必须这样做,因为这样的值不会自动保存到我们的 Filters 中没有触发任何OnChange 事件。

    3. 现在让我们为TComboBox 定义通用OnChange 事件处理程序,它将值存储到Filters

      首先,我们应该将事件处理程序的签名添加到 Form 类的 public 部分。由于 public 是类中的默认访问修饰符,您可以在组件列表或其他处理程序下添加您的函数(如果存在)

      type
        TForm1 = class(TForm)
          { here all components declaration }
          procedure ComboBoxChange(Sender: TObject);
      

      然后您可以将光标指向此声明并按 ShiftCtrlC 这应该让 IDE 生成如下所示的空函数:

      procedure TForm1.ComboBoxChange(Sender: TObject);
      begin
      
      end;
      

      我们已经为每个 ComboBox 定义了唯一的 Tag 值,因此我们可以将其用作键。事件处理程序非常简单:

      procedure TForm1.ComboBoxChange(Sender: TObject);
      begin
        with Sender as TComboBox do
          Filters.AddOrSetValue(Tag, Text);
      end;
      

      最后,您应该将此事件处理程序添加到每个 ComboBox。复制函数名称并将其粘贴到 Object InspectorEvents 选项卡中 OnChange 附近的空单元格中,对您要用于过滤的每个 ComboBox 重复此操作:

    4. 最后一步是编写函数,该函数将生成过滤查询并更新我们的事件处理程序以使用 ADOTable。让我们在 Form 类的私有部分定义我们的函数:

      type
      TForm1 = class(TForm)
        { here all components declaration }
      strict private
        Filters: TDictionary<Integer, string>;
        function GetFilterQuery(SkipEmptyValues: Boolean = False): string;
      

      ShiftCtrlC 生成函数。在函数中,我们将使用for ... in 循环遍历Filters,使用string.FormatFiltersstring.Join 的每个元素创建过滤器字符串以加入所有创建的字符串(我使用了TList&lt;string&gt;作为临时数据容器)

      function TForm1.GetFilterQuery(SkipEmptyValues: Boolean): string;
      var
        Pair: TPair<Integer, string>;
        Conditions: TList<string>;
      begin
        result := string.Empty;
        Conditions := TList<string>.Create;
      
        for Pair in Filters do
          with Pair do
            if (not SkipEmptyValues) or (not Value.IsEmpty) then
              Conditions.Add(string.Format('field%d=%s', [Key, Value.QuotedString]));
      
        if Conditions.Count > 0 then
          result := string.Join(' and ', Conditions.ToArray);
      
        Conditions.Free;
      end;
      

      最后,我们应该在 OnChange 事件处理程序中调用这个函数:

      procedure TForm1.ComboBoxChange(Sender: TObject);
      var
        Query: string;
      begin
        with Sender as TComboBox do
          Filters.AddOrSetValue(Tag, Text);
      
        Query := GetFilterQuery(True);
        if not Query.IsEmpty then
        begin
          ADOTable1.Filtered := False;
          ADOTable1.Filter := Query;
          ADOTable1.Filtered := True;
        end;
      end;
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-15
      • 2021-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-23
      • 2020-06-06
      • 1970-01-01
      相关资源
      最近更新 更多