起步软件技术论坛-X3

 找回密码
 立即注册
搜索
查看: 1405|回复: 18

[分享]从零开始做主界面**

[复制链接]
发表于 2008-6-23 10:57:55 | 显示全部楼层 |阅读模式
http://bbs.justep.com/forum.php?mod=viewthread&tid=23994 我们可以在X3平台提供的简洁风格的基础上,修改界面得到我们需要的主界面。

如果我们希望的主界面跟简洁风格的差异很大,很难直接改出来,就需要自己从零开始做主界面了。
主要涉及以下内容:
1) 登录窗体
2) 如何得到功能树
3) 如何根据功能的BizURL运行功能
4) 如何得到功能的业务关联

附件是我做的一个例子,请解压缩以后,用业务资源管理器复制粘贴到平台中使用

myui.rar

21.05 KB, 下载次数: 229

回复

使用道具 举报

 楼主| 发表于 2008-6-23 11:04:57 | 显示全部楼层
以下详细的把上述例子的步骤以及需要注意的事项进行说明
1) 创建一个空间,ID为MyUI,显示名称为“我的界面方案”
2) 在这个空间下创建一个文件夹,ID为WJJ,显示名称为“界面库”
3) 在文件夹上新建一个资源集,从 系统空间用户界面基础\界面库系统接口 继承,ID为SYSTEMINTERFACE(ID必须是这个,不能修改成其他的),显示名称为“系统接口”
4) 在系统接口上新建两个窗体
  一个ID是LOGONFORM,显示名称为“我的登陆框”
  一个ID是MYMAINFORM,显示名称为“我的主窗体”

1.png

2.42 KB, 下载次数: 821

回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-6-23 11:26:20 | 显示全部楼层

登录对话框

5) 在我的登陆框上,放两个TEdit(edtUserName, edtPassword),分别用来输入用户名和密码
放两个按钮,确定和取消
在确定按钮的OnClick事件中,检查edtUserName是否为空,当然也可以检查其他需要检查的,这里我做的检查只是用户名是否为空
procedure TLogonForm.BitBtn1Click(Sender: TObject);
begin
  if Length(edtUserName.Text)=0 then
  begin
    edtUserName.SetFocus;
    Dialogs.MessageDlg('请输入用户', TMsgDlgType.mtError, [TMsgDlgBtn.mbOK] , 0);
    Exit;
  end;

  ModalResult := Business.Forms.Controls.mrOK;
end;

声明一个静态函数ShowLogonForm,给系统接口调用时使用
static function TLogonForm.ShowLogonForm(var AName, APass: string;
      out APerson: TPersonMember; ACanAutoPosition: Boolean): Boolean;
begin
  APerson := nil;
  with TLogonForm.Create(nil) do
    try
      edtUserName.Text := AName;
      edtPassword.Text := APass;
      Result := ShowModal = Business.Forms.Controls.mrOK;
      if Result then
      begin
        AName := edtUserName.Text;
        APass := edtPassword.Text;
        APerson := nil;
        Forms.Application.ProcessMessages;
      end;
    finally
      Free;
    end;
end;

这里我没有让选择岗位,相当于缺省的自动岗位模式,如果需要选择岗位,则需要设置APerson返回值了

1.png

4.4 KB, 下载次数: 828

回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-6-23 11:28:24 | 显示全部楼层
6) 在我的系统接口资源集中,重载 ShowLogonFormEx 来调用我的登录对话框的ShowLogonForm静态函数
function TSYSTEMINTERFACE.ShowLogonFormEx(var ALogonID, APassword: string;
  out APerson: TPersonMember): Boolean;
begin
  Result := TLogonForm.ShowLogonForm(ALogonID, APassword, APerson, True);
end;
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-6-23 11:29:41 | 显示全部楼层
7) 在我的系统接口资源集上,需要引入
    协同系统\关联\业务关联库
    系统空间\系统运行库\系统核心库
    系统空间\系统运行库\系统函数库
    系统空间\用户界面基础\界面库\组件库
并且在我的主界面的代码中需要Uses中增加以下单元名
uses
  RelevancyLib, SystemCore, SystemUtils, ComponentsLib;

在我的系统接口资源集中,重载 CreateMainForm 来创建我的主界面作为主界面使用
function TSYSTEMINTERFACE.CreateMainForm(AContext: TContext): TForm;
begin
  Result := TMyMainForm.Create(AContext);
end;
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-6-23 11:34:25 | 显示全部楼层
8) 在我的主界面上,放一个TreeView,Name为tvFuncTree,作为功能树来显示到主界面上
这里我做的主界面是显示当前登陆者的每一个岗位,在岗位下显示这个岗位下分配的功能
每一个岗位下得到分配的功能,然后用TUserBizTreeView来表现这些功能,然后把TUserBizTreeView的所有节点都复制到tvFuncTree的岗位节点下面。
以下是显示功能树的代码
// 获取岗位的显示名称
function GetPositionStr(Value: TOperatorPosition): String;
begin
  Result := StringUtils.Copy(Bizsys.ObjectInfo(Value.PersonMember.BizURL).DisplayNamePath, 11, 100);
  Exit;
  Result := SysUtils.Format('部门:%s(%s)', [
    Org.OrgSys.OrgSystem.FindUnit(Value.DeptID, '', '').DisplayName,
    OrgSys.OrgSystem.GetMemberDisplayName(Value.PersonMember)] );
end;

// BizTreeView缺省是不展开的,在点击节点时候再动态加载展开的
// 此处需要复制节点到功能树,因此需要代码展开BizTreeView
procedure ExpandBizTree(ATreeView: TBizTreeView);
var
  lNode: TTreeNode;
begin
  lNode := ATreeView.Items.GetFirstNode;
  while lNode<>nil do
  begin
    lNode.Expand(True);
    lNode := lNode.getNextSibling
  end;
end;

procedure TMyMainForm.ShowFuncTree;
var
  i: Integer;
  lNode: TTreeNode;
  lFuncURLs: TStringList;
  tv: TUserBizTreeView;
begin
  tvFuncTree.Items.Clear;
  for i:=0 to TSystemCore.Operator.PositionCount-1 do
  begin
    lNode := tvFuncTree.Items.AddChildObject(nil, GetPositionStr(TSystemCore.Operator.Positions), TSystemCore.Operator.Positions);
    if TSystemCore.Operator.DefaultPosition=TSystemCore.Operator.Positions then
      lNode.Text := '缺省岗位:'+lNode.Text;
    if TOrgUtils.IsDeputized(TSystemCore.Operator.Positions) then
      lNode.Text := '代理岗位:'+lNode.Text;

    lFuncURLs := TStringList.Create;
    // 得到岗位的功能权限列表
    TContextUtils.GetAllocatedFuncs(TSystemCore.Operator.Positions.Context, lFuncURLs);
    tv := TUserBizTreeView.Create(nil);
    try
      tv.ShowOptions := [TBizObjectKind.boBizServer, TBizObjectKind.boSpace,
        TBizObjectKind.boFolder, TBizObjectKind.boBizFuncSpace, TBizObjectKind.boFunc];
      tv.Parent := Self;
      tv.ReloadTree;
      tv.IncludeFiles.Clear;
      // 把功能权限列表的URL转换成FileName的形式
      TSystemUtils.URLs2Files(lFuncURLs, tv.IncludeFiles);
      tv.UseIncludeFiles := True;
      ExpandBizTree(tv);
      CopyTreeToNode(TTreeView(tv), lNode);
      tvFuncTree.Images := tv.Images;
    finally
      tv.Free;
    end;
    lFuncURLs.Free;
  end;
end;

procedure TMyMainForm.CopyTreeToNode(srcTree: TTreeView; dstNode: TTreeNode);
var
  lNode: TTreeNode;
begin
  lNode := srcTree.Items.GetFirstNode;
  while lNode<>nil do
  begin
    CopyNodeToNode(lNode, dstNode);
    lNode := lNode.getNextSibling;
  end;
end;

procedure TMyMainForm.CopyNodeToNode(srcNode, dstNode: TTreeNode);
var
  lDstNode: TTreeNode;
  lSrcNode: TTreeNode;
begin
  lSrcNode := srcNode;
  lDstNode := TTreeView(dstNode.TreeView).Items.AddChildObject(DstNode, lSrcNode.Text, lSrcNode.Data);
  lDstNode.Assign(lSrcNode);
  lSrcNode := SrcNode.getFirstChild;
  while lSrcNode<>nil do
  begin
    CopyNodeToNode(lSrcNode, lDstNode);
    lSrcNode := SrcNode.GetNextChild(lSrcNode);
  end;
end;

1.png

7.4 KB, 下载次数: 811

回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-6-23 11:37:19 | 显示全部楼层
8) 在tvFuncTree的OnClick事件中,查找节点对应的岗位环境,然后在这个岗位上运行相应的功能
代码如下:
procedure TMyMainForm.tvFuncTreeClick(Sender: TObject);
var
  lNode: TTreeNode;
begin
  lNode := tvFuncTree.Selected;
  if lNode=nil then Exit;

  if lNode.Data is TOperatorFuncItem then
    RunFunc(lNode, (lNode.Data as TOperatorFuncItem).FuncURL.URL)
  else if lNode.Data is TOrgFuncAllocItem then
    RunFunc(lNode, (lNode.Data as TOrgFuncAllocItem).FuncURL)
  else if (lNode.Data is TBizNode) and (TBizNode(lNode.Data).NodeKind = TBizObjectKind.boFunc) then
    RunFunc(lNode, (lNode.Data as TBizNode).BizURL.URL);
end;

procedure TMyMainForm.RunFunc(ANode: TTreeNode; AFuncURL: String);
var
  lContext: TContext;
begin
  if FCurrentFunc<>nil then
    TSystemCore.FuncManager.TerminateFunc(FCurrentFunc, False);

  lContext := FindContext(ANode);
  CurrentFunc := TSystemCore.FuncManager.RunFunc(lContext, '', AFuncURL, '', nil, False);
end;

function TMyMainForm.FindContext(ANode: TTreeNode): TContext;
var
  lNode: TTreeNode;
begin
  Result := nil;
  lNode := ANode;
  while (lNode<>nil) do
  begin
    if (lNode.Data<>nil) and (lNode.Data is TOperatorPosition) then
    begin
      Result := (lNode.Data as TOperatorPosition).Context;
      Break;
    end;
    lNode := lNode.Parent;
  end;
end;
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-6-23 11:39:47 | 显示全部楼层
9) 在我的主界面上,放一个TPanel,Name为pnlMain,用来方当前运行的功能主窗体
这里我做的比较简单,只能有一个功能运行,在运行另外一个功能时,先结束当前运行的功能
代码如下:
procedure TMyMainForm.SetCurrentFunc(Value: TFunc);
begin
  if FCurrentFunc=Value then Exit;

  FCurrentFunc := Value;
  if FCurrentFunc.MainForm<>nil then
  begin
    FCurrentFunc.MainForm.BorderIcons := [];
    FCurrentFunc.MainForm.Caption := '';
    FCurrentFunc.MainForm.Align := TAlign.alClient;
    FCurrentFunc.MainForm.BorderStyle := TFormBorderStyle.bsNone;
    FCurrentFunc.MainForm.FormStyle := TFormStyle.fsNormal;
    FCurrentFunc.MainForm.Parent := pnlMain;
    ReloadRelevancyNavBar;
  end;
end;
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-6-23 11:46:05 | 显示全部楼层
10) 在我的主界面上,定义一个变量FRelevancyNavBar (TRelevancyNavBar),用来显示业务关联
在Create方法中创建这个对象,在Destroy方法中释放这个对象
定义一个方法ReloadRelevancyNavBar,来显示当前功能的业务关联,在这个方法中发一个刷新业务关联的消息给环境,如果没有处理这个消息(说明功能没有自定义业务关联),就调用缺省的方法DefaultRefreshRelevancies来显示业务关联条。
代码如下:
constructor TMyMainForm.Create(AContext: TContext);
begin
  inherited;

  // 业务关联条
  FRelevancyNavBar := TRelevancyManager.CreateRelevancyNavBar(Self, tabRelevancy);
  FRelevancyNavBar.FuncManager := TSystemCore.FuncManager;
  FRelevancyNavBar.DefaultStyles.Background.BackColor := 15855854;
  FRelevancyNavBar.DefaultStyles.Background.BackColor2 := 15855854;
  FRelevancyNavBar.Align := TAlign.alClient;
end;

destructor TMyMainForm.Destroy;
begin
  FreeAndNil(FRelevancyNavBar);
  inherited;
end;

procedure TMyMainForm.ReloadRelevancyNavBar;
var
  lRelevancyViewNavBar: TRelevancyViewNavBar;
  lRefreshRelevanciesMessage: TRefreshRelevanciesMessage;
  lReloadRelevanciesMessage: TReloadRelevanciesMessage;
begin
  if TRelevancyManager.IsShowRelevancyNavBar(Context, FCurrentFunc.BizClassURL.BizURL.URL) then
  begin
    FRelevancyNavBar.Clear;

    lRefreshRelevanciesMessage := TRefreshRelevanciesMessage.Create(FRelevancyNavBar);
    try
      if not FCurrentFunc.Context.SendMessage(lRefreshRelevanciesMessage) then
        DefaultRefreshRelevancies(FRelevancyNavBar);
    finally
      lRefreshRelevanciesMessage.Free;
    end;

    if FCurrentFunc <> nil then
    begin
      lRelevancyViewNavBar := TRelevancyViewNavBar.Create(FRelevancyNavBar);
      lReloadRelevanciesMessage := TReloadRelevanciesMessage.Create(lRelevancyViewNavBar);
      try
        FCurrentFunc.Context.SendMessage(lReloadRelevanciesMessage);
      finally
        lReloadRelevanciesMessage.Free;
      end;
    end;
  end;
end;

procedure TMyMainForm.DefaultRefreshRelevancies(ANavBar: TRelevancyNavBar);
var
  I, J: Integer;
  lInfo: TInfo;
begin
  for I := 0 to FCurrentFunc.Context.ChildCount - 1 do
    if FCurrentFunc.Context.Children[I].Owner is TInfo then
    begin
      lInfo := FCurrentFunc.Context.Children[I].Owner as TInfo;
      for J := 0 to lInfo.DataSetCount - 1 do
      begin
        if lInfo.DataSets[J].Active then
          ANavBar.BindDataSet(lInfo.DataSets[J]);
      end;
    end;
  ANavBar.ReloadRelevancies(FCurrentFunc.Context, FCurrentFunc.BizClassURL.BizURL.URL);
end;
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-6-23 11:52:20 | 显示全部楼层
11) 由于只能有一个功能运行,所以没有处理 SystemCore.FuncManager 的 OnFuncRun、OnFuncActivate、OnFuncTerminate事件,如果有多个功能同时运行的话,就需要截获这三个事件了。
当多个功能运行时,功能间切换时候需要调用FuncManager.ActiveFunc方法来触发OnFuncActivate事件
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Justep Inc.

GMT+8, 2025-7-20 14:38 , Processed in 0.039522 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表