【问题标题】:Delphi firemonkey tabstop problems in a tabcontrol选项卡控件中的Delphi firemonkey制表符问题
【发布时间】:2014-02-14 15:08:35
【问题描述】:

我正在为 Windows 平台在 Delphi XE5 Update 2 中编写 Firemonkey HD 程序。 我有一个tabcontrol,表单上有一个tabitem,tabitem中有一些编辑框。我相应地设置了 taborder (0,1,2,..),当我进入 Edit1 并点击 tab 时,Edit1 失去焦点但 Edit2 没有获得焦点。

我尝试将编辑框放在主窗体和面板中,它们在那里正常工作,当我在 edit1 并点击选项卡时,它会转到 edit2 等等,但在 tabcontrol 中的 tabitem 上却没有。

有没有人知道解决这个问题或者我错过的设置?

感谢您的帮助

【问题讨论】:

    标签: delphi firemonkey delphi-xe5


    【解决方案1】:

    这是针对该问题的实际解决方案,我也在 http://vldgeorgiev.wordpress.com/2014/04/01/delphi-tab-key-and-taborder-not-working 中进行了描述

    它位于FMX.TabControl.pas 单元中的TTabItem 的来源。
    有一个被覆盖的方法叫做TTabItem.DoAddObject

    procedure TTabItem.DoAddObject(const AObject: TFmxObject);
    var
      ControlTmp: TControl;
    begin
      if Assigned(FContent) and not AObject.Equals(FContent) and not AObject.Equals(ResourceLink) then
      begin
        FContent.AddObject(AObject);
    ...
    end;
    

    应该是这样的

    procedure TTabItem.DoAddObject(const AObject: TFmxObject);
    var
      ControlTmp: TControl;
    begin
      if Assigned(FContent) and not AObject.Equals(FContent) and not AObject.Equals(ResourceLink) then
      begin
        FContent.AddObject(AObject);
        AddToTabList(AObject);       // This line is missing in the original source
    ...
    end;
    

    问题在于,当表单的 KeyDown 方法处理 Tab 键时,它会调用 AdvanceTabFocus 方法,该方法会检查 FTabList 是否有任何子组件。因为 TTabItem 的原始 DoAddObject 方法缺少一行,所以它从未将子控件添加到该列表中,因此 AdvanceTabFocus 方法无法找到下一个控件。相反,它将焦点设置到窗体上的第一个控件。

    要使用此修复程序,请将修改后的 FMX.TabControl.pas 单元复制到项目文件旁边,或者编译 DCU 并将它们放在 Delphi 安装文件夹的 Lib... 子文件夹中。如果你没有资源,那你就倒霉了。

    顺便说一句,设置 TabOrder 数字并不总是足够的。您必须右键单击并使用“Tab order...”,甚至在表单文本中手动重新排序控件(使用 Alt-F12)

    【讨论】:

    • 我的主窗体中有一个 tabcontrol,我在其中插入 Frames,此修复解决了选项卡字段的问题
    【解决方案2】:

    这是一个已知的错误: http://qc.embarcadero.com/wc/qcmain.aspx?d=117380

    看起来它可能已针对 XE6 修复。

    您可以使用Control.SetFocus 手动设置焦点,但您必须为每个控件自行设置。您可以设置 OnKeyUp 事件并查看他们是否按下了选项卡(VK_TAB 或 9),以及他们是否确实将焦点设置到了您的下一个控件。

    【讨论】:

    • 感谢质量控制链接。我开始手动操作,但有 50 个控件,其中一些有时被隐藏起来,这变得非常乏味。我将不得不看看是否有一种方法可以以编程方式进行,taborder 已经存在。我需要通过所有的控制,看看谁是下一个。或者也许将它们存储在一个数组中。再次感谢您的帮助
    • 请注意QualityCentral has now been shut down,因此您无法再访问qc.embarcadero.com 链接。如果您需要访问旧的 QC 数据,请查看 QCScraper
    【解决方案3】:

    我以一种非常简单的方式解决了这个问题。 我将表单的高度更改为 2000 并将字段插入到我的滚动框中。 然后我将表单的高度恢复为原始高度。 据我了解,当组件位于滚动框的可见区域之外时,firemonkey 会丢失。但是如果表单的高度较大,滚动框就会认为一切都是可见的并且可以正常工作。

    【讨论】:

    • 你能提供包含你的解决方案的代码sn-p吗?
    【解决方案4】:

    我在我的应用程序中遇到了同样的问题,所以我写了一个解决方法:

    http://andydunkel.net/delphi/coding/2013/11/23/firemonkey_xe_4_taborder_workaround.html

    我正在使用 FormHelper 类、Form 的 key down 方法(对 Tab 键作出反应)和控件的帮助上下文属性。

    首先我设置了帮助上下文,例如,您也可以使用标签。但我已经将 tag 属性用于其他用途:

    unit FormHelper;
    
    interface
    
    type
      TFormHelper = class helper for TForm
        procedure DoTabHandlingXE(comp : TForm; tabOrder : Integer);
      end;
    
    implementation
    
    //Workaround for Tab-Bug in Firemonkey
    procedure TFormHelper.DoTabHandlingXE(comp: TForm; tabOrder : Integer);
    var
      i, c :integer;
      current : TComponent;
      currentNext : integer;
      focus : TStyledControl;
    begin
      c := Self.ComponentCount - 1;
      currentNext := 9999;
      focus := nil;
    
      for i := 0 to c do begin
          current := Self.Components[i];
          if (current is TStyledControl) then begin
              if ((current as TStyledControl).HelpContext < currentNext) and 
              ((current as TStyledControl).HelpContext > tabOrder) then begin
                currentNext := (current as TStyledControl).HelpContext;
              end;
          end;
      end;  
    
      for i := 0 to c do begin
          current := Self.Components[i];
          if (current is TStyledControl) then begin
            if (currentNext = (current as TStyledControl).HelpContext) then begin
              focus := (current as TStyledControl);
            end;
          end;
      end;
    
      if focus <> nil then begin
        focus.SetFocus;
    end;
    end;
    end.
    

    当然,代码没有做任何事情,因为该方法还没有被调用。所以下一步就是在表单中实现KeyDown事件:

    procedure TfrmEinzField.KeyDown(var Key: Word; var KeyChar: Char;
      Shift: TShiftState);
    var
      control : TStyledControl;
    begin
      if Key = vkTab then
      begin
        //custom handling
        if (Self.GetFocused is TStyledControl) then begin
          control := (Self.GetFocused as TStyledControl);
          DoTabHandlingXE(Self, control.HelpContext);
        end;
      end else
        inherited; //do default handling
    end;
    

    在代码中,我们得到了当前聚焦的控件。然后我们用当前的Form变量和控件的HelpContext值调用我们之前写的方法。使用该解决方法,tab 键现在按预期工作,跳转到下一个控件。

    更多细节在博文中。

    【讨论】:

      【解决方案5】:

      我遇到了同样的问题并找到了一个简单的解决方法:只需确保创建顺序是您的 Tab 键顺序。您可以通过编辑(文本)表单文件 (.fmx) 来做到这一点。 (在表单设计模式下按 F12) 例如: 如果您有一个只有 3 个编辑控件的表单,则 for 看起来像这样:

      object Form1: TForm1
        Left = 0
        Top = 0
        Caption = 'Form1'
        ClientHeight = 154
        ClientWidth = 215
        FormFactor.Width = 320
        FormFactor.Height = 480
        FormFactor.Devices = [dkDesktop, dkiPhone, dkiPad]
        DesignerMobile = False
        DesignerWidth = 0
        DesignerHeight = 0
        DesignerDeviceName = ''
        DesignerOrientation = 0
        DesignerOSVersion = ''
        object Edit1: TEdit
          Touch.InteractiveGestures = [igLongTap, igDoubleTap]
          TabOrder = 0
          Position.X = 40.000000000000000000
          Position.Y = 88.000000000000000000
          Width = 100.000000000000000000
          Height = 22.000000000000000000
          KillFocusByReturn = False
        end
        object Edit2: TEdit
          Touch.InteractiveGestures = [igLongTap, igDoubleTap]
          TabOrder = 1
          Position.X = 40.000000000000000000
          Position.Y = 56.000000000000000000
          Width = 100.000000000000000000
          Height = 22.000000000000000000
          KillFocusByReturn = False
        end
        object Edit3: TEdit
          Touch.InteractiveGestures = [igLongTap, igDoubleTap]
          TabOrder = 2
          Position.X = 40.000000000000000000
          Position.Y = 24.000000000000000000
          Width = 100.000000000000000000
          Height = 22.000000000000000000
          KillFocusByReturn = False
        end
      end
      

      Tab 顺序为 Edit1:、Edit2:、Edit3:

      如果你把它改成:

      object Form1: TForm1
        Left = 0
        Top = 0
        Caption = 'Form1'
        ClientHeight = 154
        ClientWidth = 215
        FormFactor.Width = 320
        FormFactor.Height = 480
        FormFactor.Devices = [dkDesktop, dkiPhone, dkiPad]
        DesignerMobile = False
        DesignerWidth = 0
        DesignerHeight = 0
        DesignerDeviceName = ''
        DesignerOrientation = 0
        DesignerOSVersion = ''
        object Edit1: TEdit
          Touch.InteractiveGestures = [igLongTap, igDoubleTap]
          TabOrder = 0
          Position.X = 40.000000000000000000
          Position.Y = 88.000000000000000000
          Width = 100.000000000000000000
          Height = 22.000000000000000000
          KillFocusByReturn = False
        end
        object Edit3: TEdit
          Touch.InteractiveGestures = [igLongTap, igDoubleTap]
          TabOrder = 2
          Position.X = 40.000000000000000000
          Position.Y = 24.000000000000000000
          Width = 100.000000000000000000
          Height = 22.000000000000000000
          KillFocusByReturn = False
        end
        object Edit2: TEdit
          Touch.InteractiveGestures = [igLongTap, igDoubleTap]
          TabOrder = 1
          Position.X = 40.000000000000000000
          Position.Y = 56.000000000000000000
          Width = 100.000000000000000000
          Height = 22.000000000000000000
          KillFocusByReturn = False
        end
      end
      

      比tab顺序是Edit1:,Edit3:,Edit2:不管TabOrder属性的值是什么

      【讨论】:

      • 请说明您在代码中所做的更改,复制粘贴不够明确。
      猜你喜欢
      • 2018-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-08
      相关资源
      最近更新 更多