【问题标题】:How to allow or forbid user to enter tab in pagecontrol?如何允许或禁止用户在页面控件中输入选项卡?
【发布时间】:2011-12-05 10:05:42
【问题描述】:

我想限制用户(基于特殊条件)在页面控件中打开或不打开选项卡。即,用户可以单击选项卡,但不会向他显示。相反,会向他显示一条消息“he don't have the access right to see such tab”。

我应该在什么事件上编写检查代码,以及(TPageControl 组件的)哪个选项卡属性将允许/阻止用户进入此类选项卡?

【问题讨论】:

  • 如果用户无论如何都看不到内容,为什么要首先显示选项卡??
  • 您能否更详细地解释正在发生的情况?然后,我们可以为您的任务推荐安全和 GUI 标准的最佳做法。
  • 当然,我正在设计一个员工屏幕,其中包含个人信息、他的合同信息和家庭信息,每个都在 diffrenet 选项卡中。因此具有特权的超级用户可以看到合同信息,但另一个具有较少特权的用户必须只看到家庭信息并对其进行编辑,但不能看到他的合同信息(如薪水、津贴等)。请如果您有更好的设计,您将挽救我的生命(和我的工作)。谢谢大家

标签: delphi tpagecontrol


【解决方案1】:

在理想情况下,您可以将OnChanging 事件中的AllowChange 设置为False 以阻止页面更改。但是,这似乎不可行,因为我无法从 OnChanging 中辨别出用户正在尝试选择哪个页面。

即使查看底层的 Windows 通知似乎也没什么希望。 TCN_SELCHANGING 通知标识了控件,但据我所知并没有说明所涉及的页面。

我能想到的最好方法是使用OnChanging 记录当前活动页面,然后在OnChange 中进行艰苦的工作。如果所选页面已更改为不受欢迎的内容,则只需将其更改回来。

procedure TForm1.PageControl1Changing(Sender: TObject; var AllowChange: Boolean);
begin
  FPreviousPageIndex := PageControl1.ActivePageIndex;
end;

procedure TForm1.PageControl1Change(Sender: TObject);
begin
  if PageControl1.ActivePageIndex=1 then begin
    PageControl1.ActivePageIndex := FPreviousPageIndex;
    Beep;
  end;
end;

我知道有点乱,但它有工作的优点!

【讨论】:

  • 如果您在 self.PageControl1.ActivePageIndex:= 1; 等代码中更改 de activePageIndex 将不起作用
  • @Ravaut123 确实不是。既然你控制你写的代码,应该很容易避免出现这样的错误。
【解决方案2】:

OnChanging 事件不允许您确定选择了哪个选项卡,因为 Windows 本身不会报告该信息。但是,您可以做的是子类化TPageControl.WindowProc 属性,以在处理它们之前拦截发送到TPageControl 的消息。使用鼠标消息来确定直接单击哪个选项卡(查看TPageControl.IndexOfTabAt() 方法),并使用键盘消息来检测左/右箭头按下以确定哪个选项卡与活动选项卡相邻(查看TPageControl.FindNextPage()方法)。

【讨论】:

    【解决方案3】:

    使用页面控件的OnChanging事件。

    procedure TForm1.PageControl1Changing(Sender: TObject; var AllowChange: Boolean);
    begin
      if (self.PageControl1.TabIndex= 1)and
         (NotAllowUser = 'SomePerson') then
      begin
        AllowChange:= False;
        ShowMessage('Person not allow for this Tab');
      end;
     end;
    

    好的,PageControle1.TabIndex 是 activepageindex,而不是我要选择的那个。 我怎样才能获得点击的页面。

    procedure TForm1.PageControl1Changing(Sender: TObject; var AllowChange: Boolean);
    var
      P: TPoint;
      NewTabIndex: Integer;
    begin
    
      P := PageControl1.ScreenToClient(Mouse.CursorPos);
      NewTabIndex := PageControl1.IndexOfTabAt(P.X, P.y);
    
      if (NewTabIndex= 1) then
      begin
        AllowChange:= false;
        Beep
      end;
    end;
    

    新尝试

     TMyPageControl = Class(TPageControl)
     private
       FNewTabSheet: TTabSheet;
       FOnMyChanging: TMyTabChangingEvent;
       procedure SetOnMyChanging(const Value: TMyTabChangingEvent);
       procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
       procedure CMDialogKey(var Message: TCMDialogKey); message CM_DIALOGKEY;
     protected
       function CanChange: Boolean; Override;
     public
       property OnMyChanging: TMyTabChangingEvent read FOnMyChanging write SetOnMyChanging;
     End;
    
    
    
     { TMyPageControl }
    
    
    
    
     function TMyPageControl.CanChange: Boolean;
     begin
       Result := True;
       if Assigned(FOnMyChanging) then FOnMyChanging(Self, FNewTabSheet ,Result);
     end;
    
    
    
     procedure TMyPageControl.CMDialogKey(var Message: TCMDialogKey);
     begin
       if (Focused or Windows.IsChild(Handle, Windows.GetFocus)) and
          (Message.CharCode = VK_TAB) and (GetKeyState(VK_CONTROL) < 0) then
       begin
         FNewTabSheet := FindNextPage(ActivePage, GetKeyState(VK_SHIFT) >= 0,True);
         SelectNextPage(GetKeyState(VK_SHIFT) >= 0);
         Message.Result := 1;
       end else
        inherited;
     end;
    
     procedure TMyPageControl.CNNotify(var Message: TWMNotify);
     var
       P: TPoint;
       NewTabIndex: Integer;
     begin
         with Message do
         case NMHdr.code of
           TCN_SELCHANGE:
             Change;
           TCN_SELCHANGING:
             begin
               Result := 1;
                 P := self.ScreenToClient(Mouse.CursorPos);
                NewTabIndex := self.IndexOfTabAt(P.X, P.y);
                FNewTabSheet:= self.Pages[NewTabIndex];
               if CanChange then Result := 0;
             end;
         end;
     end;
    
     procedure TMyPageControl.SetOnMyChanging(const Value: TMyTabChangingEvent);
     begin
       FOnMyChanging := Value;
     end;
    

    【讨论】:

    • 这不会按要求工作,因为 TabIndex 属性将在 OnChanging 事件期间为您提供当前活动选项卡的索引,而不是新选择的选项卡。
    • 遗憾的是这不起作用,因为 TabIndex 是当前选择的页面,而不是用户试图选择的页面
    • 我更改代码以获取用户想要的选定 PageIndex。
    • @Ravault - 也可以使用 Ctrl+Tab 或在选项卡按钮处于活动状态时使用箭头切换到新选项卡。
    • @David - 不,我同意您在回答中的评估。不过我不喜欢这个解决方案..
    【解决方案4】:

    有时最好用这样的方式隐藏不需要的 TabSheets:

    TabSheetNN.TabVisible:=Somecondition;
    

    而不是试图阻止切换到这些选项卡。 当然,如果 OnChanging 事件中的 Sender 是 TabSheet 而不是 TPageControl 会更好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-10
      • 2013-07-21
      • 1970-01-01
      • 2018-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多