第十章操作界面与操作逻辑

我们在前面的曾经讨论过,用户界面与商业逻辑分离的好处。这样的分离可以让软件体系结构更加合理,结构易于理解,从而增强软件的灵活性和可维护性。
正如我谈到过,我们讨论的目的是为了寻找将软件结构从混沌归于有序的实用方法,这是编写本书的主要目的之一。有序的东西易于理解,易于理解就便于掌握,掌握之后你将会发现其背后的哲理是那样的简单,从而升华到更高的境界去感受良好软件结构的协调美。
本章的话题将重点讨论如何将客户端的程序有序化,希望我们的讨论对所有的软件同行和朋友都有所帮助。

第一节分离操作界面与操作逻辑
怎样设计友好的软件操作界面,是人机工程学研究的一个重要课题。好用的软件都有清秀可爱的面容,不但布局匀称合理,对你的操作意图也是善解人意,并且处理大方得体,就连对你的回答也体贴入微。如果,你编写的软件象这样将关键字重复的错误告诉你的用户:“亲爱的,你以前已经输入了编号为991028的出库单,不可重复输入。是否想查看以前的出库单呢?”,你的软件一定会销量大增。可能当年IBM的OS2就是因为说了很多用户看不懂的废话,才被用户遗弃,失去民心,而被Bill Gates一统天下。
我们今天不打算讨论怎样打扮软件的容颜,而要谈谈在漂亮的界面后面,应该如何更好地组织软件结构,大大方方地处理用户的操作命令。
假如,你已经规划好软件初步的操作模式,用带图标的菜单作为用户发号司令的工具,并在MenuItem的OnClick事件中编写完成业务处理的过程语句。一切都不错,而商业的逻辑处理也是放到服务器端的RemoteDataMoudle中处理的,经典的三层体系结构。可是你的老板不喜欢菜单,他对按钮情有独钟,于是你需要将Menu换成Button,然后将操作实现代码移到Button的OnClick事件过程中,或者将Button的OnClick事件指向原来的MenuItemClick事件处理过程。软件提交用户试用之后,用户强烈要求将软件修改为Microsoft Word 2000那样的界面,既有菜单又有按钮,而且还能提供键盘的快捷键输入(因为他们的老总习惯了原来DOS下那套老程序的键盘输入方式)。于是,你又不得不修改软件的界面控件,并再次将操作处理代码调整,以便每种命令输入方式都能被响应。最后,历经千辛万苦终于能完成整个软件界面的修改工作。
由此可见,不同的人有不同的爱好和需求,他们各自都有操作软件的习惯。但是他们使用软件的目的是相同的,就是,向你的软件发出指定的操作指令,使用该操作所代表的软件功能!
在种种不同的用户的需求之中,搞清所有用户的最终目的之后,我们应该仔细地想一想,不同的用户为了达到相同目的,使用了不同的手段。哦!原来目的和手段是两回事,只不过每个人用不同的手段达到相同的目的。
因此,我们应该将操作界面与操作逻辑分离,应该首先分清手段和目的,然后将手段与目的联系起来。这样,操作界面的更改将不会影响到操作逻辑,手段是手段,目的是目的。为了达到目的,可以不择手段,就是这个道理!
说道这里,也许有人会说:这个道理谁都懂。那么,如果在我们开发软件的过程中,多运用这些浅显的道理,就不难设计出简单而又实用的软件结构。
操作界面与操作逻辑的分离可以为我们带来哪些好处呢?
1.易于理解
你可以在编写业务操作代码时,不关心软件的界面操作模式,而在美化你的软件时,只考虑界面的美学问题。外表是外表,内心是内心,只有你知道,外表美观的界面连接着精巧内秀的操作代码,表里如一。你的朋友们既可欣赏到漂亮的软件外表,也容易读懂你的内心。

2.易于维护
不管将来流行什么软件界面,是时新HomePage式样还是OutLook的经典面版。你可以只修改与界面有关的部分,就可满足要求。也可将你的软件彻底改头换面,以崭新的面容出现。甚至,可表演川剧名家传内不传外传男不传女的独门绝技-变脸。但软件还是软件,软件的内在功能逻辑并未改变。不过,由于满足了用户喜新厌旧,追逐流行时尚的习惯,将使软件公司的老板们的腰包越来越鼓。

3.可扩充性强
人机工程学不断取得的新突破,将为软件使用者提供更多的命令输入方式。现在,语音识别技术已逐渐商用化。你已经可以利用IBM ViaVoice提供的语音识别支持模块,开发能识别语音命令的控件。将这样的控件加入你的软件中,并与你以前编写的操作逻辑关联,你的软件就象长了耳朵,有了灵气,可以倾听你的述说。我也相信,总有一天可编写一种可以看懂你的表情的控件,那么,软件将可以根据你的情绪对你抚以不同冷暖的关怀。但软件的灵魂还是原来的操作逻辑代码!

4.适合大规模软件开发
大规模软件开发讲求分工协作,各尽其才。如果你是软件公司的老板,那么,在系统分析设计人员完成软件设计之后,你可以找一批时装设计师为你的软件设计漂亮性感的界面,请精于编码的程序员编写操作逻辑。而你可以轻松地管理和控制各道工序的质量,而且责任分明。

尽管天涯海角的吹了一通,但我们还得回到我们主题。操作界面与操作逻辑的分离,到底要遵循哪些方法和原则呢?
首先,你应当归纳整理当前模块要向用户提供的功能,划分出明确的操作命令集。也就是说,设计可提供给用户的命令,这有点象老式命令行程序的可用命令清单列表。记住,这些命令集体现的是用户执行操作的目的。
然后,在根据命令集中的每一命令规划操作逻辑代码,按照编写程序的一般原则编制操作逻辑代码。有关编写程序的一般原则,可参阅《初恋DELPHI》一书。
最后,要提醒一点的就是,操作命令有时是受程序状态控制的。有的程序员为了实现在某中状态下禁止用户发出指定的操作命令,想尽办法控制菜单、按钮等命令控件的属性,封杀和打压所有可执行命令的控件。但是,你想禁止的是命令,而不是控件!
下面我们将会讨论在分离操作界面和操作逻辑方面,DELPHI为我们提供的很有价值的东西,即TActionList和TAction。

第二节使用TActionList和TAction
“Action”一词的含义是行为、行动或动作,TAction就是抽象了用户想要通过软件界面表现的行为、开展的行动或执行的动作,而TActionList就描述了动作的命令清单。你可以将一个TActionList元件加入到你的Form、Frame或DataModule中,双击此元件可定义需要的TAction对象。
缔造DELPHI大厦的设计师和工程师们,为绝大多数命令控件(如TButton,TMenuItem等等)设计了Action属性,并且常常碰巧出现在Object Inspecter窗口属性页面的第一项上,由此可见他们的用心良苦。但不管怎样,他们为我们提供了一个简单的方法,将命令控件的Action属性与TActionList元件中定义的TAction对象关联。
由于,在TAction对象的OnExecute事件中编写的操作逻辑代码可自动被关联的命令控件调用,因此,更换命令控件的类型,不用修改或调整操作逻辑代码。这样就可将操作界面与操作逻辑分开。
如果在某些状态下你要禁止用户执行某种操作,可设置相关TAction对象的Enabled属性为FALSE,则相关的命令控件将通通被冷冻,该变白脸的变脸白,该变灰脸的变灰脸,而不管他是生旦净末丑。
再次感谢缔造DELPHI的大师们,是他们在台后为我们做了一切,而且还将他们的九阴真经放到Source/VCL/ActnList.pas单元中。
既然有大师们的九阴真经,我们就应该拿来修炼,增强我们的内功。
首先,在ActnList单元中,TActionList是这样声明的:
TActionList = class(TCustomActionList)
published
property Images;
property OnChange;
property OnExecute;
property OnUpdate;
end;
TActionList只发表了TCustomActionList的一些属性和事件。其实,TActionList就是用来装TAction的容器,并提供了管理TAction的方法。有关TActionList的详细用法,我们将在随后开发的TActionManager控件中讨论。

再来看看TAction的声明的:
TAction = class(TCustomAction)
published
property Caption;
property Checked;
property Enabled;
property HelpContext;
property Hint;
property ImageIndex;
property ShortCut;
property Visible;
property OnExecute;
property OnHint;
property OnUpdate;
end;
TAction是从TCustomAction类继承的,与前面一样,只不过将父类的一些特征发表。我不想逐一解读TAction的各个类层次的原代码,相信读过《初恋DELPHI》一书的朋友都能够解读这些代码。我只想讨论TAction发表给我们的这些特性,能为我们提供什么功能。由于还有一些特性是在TAction的父辈类中发表的,在讨论时也将一起谈到,不过一些不重要的特性就不再废话了。
Caption属性:填写此属性,你可以用简短的标题向用户说明命令操作的含义。此属性将自动更新相关命令控件的Caption属性,所以按钮和菜单的Caption属性要在此输入。
Category属性:操作命令的类别,主要是为了方便你分类管理你的操作命令集。此属性是在TAction的爷爷辈TContainedAction中发表的,在我们随后开发的TActionManager控件中,你将看到如何此属性管理操作命令。
Enabled属性:控制命令操作是否可执行,可自动控制关联命令控件是否允许执行。封杀命令控件应该从这里下手。
ImageIndex属性:表示操作命令的图标索引,与TActionList的Images联系。有图标的命令控件可以享受到他的恩惠。
ShortCut属性:用键盘发出操作命令的快捷键,为喜好键盘操作的人们带来的福音。
Visible属性:控制Enabled可以让命令控件变灰,控制此属性可以让命令控件消失在用户面前。注意,虽然命令控件消失,但用户仍可通过快捷键发出操作命令,而Enabled才可真正封杀命令。
OnExecute事件:可以在此事件中编写操作逻辑代码,用户触发相关的命令控件时,将自动调用此事件的操作逻辑代码。
其他的特性就自己查看DELPHI的联机帮助吧!
初步了解TActionList和TAction之后,我们将开始实践。下面的PRETTYPOEM程序演示了TActionList和TAction的基本用法,很简单。如果你不想浪费时间可直接跳到后面的MULTIFACE程序,看看如何表演川剧的绝活儿-变脸。
你可以在随书所附的光盘中找到此程序的原代码。

文件PRETTYPOEM.DPR

program PRETTYPOEM;

uses
Forms,
Main in 'Main.pas' {fMain};

{$R *.RES}

begin
Application.Initialize;
Application.CreateForm(TfMain, fMain);
Application.Run;
end.

文件Main.pas
unit Main;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Menus, ActnList, ComCtrls, ToolWin, StdCtrls, ImgList;

type
TfMain = class(TForm)
MainMenu: TMainMenu;
ActionList: TActionList;
actGuCheng: TAction;
actXiMuRong: TAction;
actLiQingZhao: TAction;
actSuShi: TAction;
N1: TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
N4: TMenuItem;
N5: TMenuItem;
N6: TMenuItem;
ToolBar1: TToolBar;
ToolButton1: TToolButton;
ToolButton2: TToolButton;
ToolButton3: TToolButton;
ToolButton4: TToolButton;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
cbDisableLiQingZhao: TCheckBox;
actDisableLiQingZhao: TAction;
actHideLiQingZhao: TAction;
cbHideLiQingZhao: TCheckBox;
ImageList: TImageList;
labPoem: TLabel;
labShadow: TLabel;
procedure actGuChengExecute(Sender: TObject);
procedure actXiMuRongExecute(Sender: TObject);
procedure actDisableLiQingZhaoExecute(Sender: TObject);
procedure actHideLiQingZhaoExecute(Sender: TObject);
procedure actSuShiExecute(Sender: TObject);
procedure actLiQingZhaoExecute(Sender: TObject);
private
{ Private declarations }
procedure RecitePoem(Poem:string);
public
{ Public declarations }
end;

var
fMain: TfMain;

implementation

{$R *.DFM}
procedure TfMain.RecitePoem(Poem: string);
begin
labPoem.Caption:=Poem;
labShadow.Caption:=Poem;
end;

procedure TfMain.actGuChengExecute(Sender: TObject);
begin
RecitePoem('黑夜给我黑色的眼睛我却用她寻找光明');
end;

procedure TfMain.actXiMuRongExecute(Sender: TObject);
begin
RecitePoem('溪水急着要流向大海而浪潮却渴望重归土地');
end;

procedure TfMain.actSuShiExecute(Sender: TObject);
begin
RecitePoem('人有悲欢离合月有阴晴圆缺');
end;

procedure TfMain.actLiQingZhaoExecute(Sender: TObject);
begin
RecitePoem('生当做人杰死亦为鬼雄');
end;

procedure TfMain.actDisableLiQingZhaoExecute(Sender: TObject);
begin
actLiQingZhao.Enabled:=not cbDisableLiQingZhao.Checked;
end;

procedure TfMain.actHideLiQingZhaoExecute(Sender: TObject);
begin
actLiQingZhao.Visible:=not cbHideLiQingZhao.Checked;
end;

end.

文件Main.dfm

object fMain: TfMain
Left = 192
Top = 107
Width = 442
Height = 195
BorderIcons =[biSystemMenu, biMinimize]
Caption = '谈古论今'
Color = clBtnFace
Font.Charset = GB2312_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = '宋体'
Font.Style =[]
Menu = MainMenu
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 12
object labShadow: TLabel
Left = 17
Top = 41
Width = 380
Height = 20
Caption = '古今诗词名句欣赏,请选择你喜爱的诗人。'
Font.Charset = GB2312_CHARSET
Font.Color = clBlack
Font.Height = -20
Font.Name = '隶书'
Font.Style = []
ParentFont = False
Transparent = True
end
object labPoem: TLabel
Left = 16
Top = 40
Width = 380
Height = 20
Caption = '古今诗词名句欣赏,请选择你喜爱的诗人。'
Font.Charset = GB2312_CHARSET
Font.Color = clBlue
Font.Height = -20
Font.Name = '隶书'
Font.Style = []
ParentFont = False
Transparent = True
end
object ToolBar1: TToolBar
Left = 0
Top = 0
Width = 434
Height = 26
AutoSize = True
ButtonWidth = 63
Caption = 'ToolBar'
EdgeBorders = [ebTop, ebBottom]
Flat = True
Images = ImageList
List = True
ShowCaptions = True
TabOrder = 0
object ToolButton1: TToolButton
Left = 0
Top = 0
Action = actGuCheng
end
object ToolButton2: TToolButton
Left = 63
Top = 0
Action = actXiMuRong
end
object ToolButton3: TToolButton
Left = 126
Top = 0
Action = actSuShi
end
object ToolButton4: TToolButton
Left = 189
Top = 0
Action = actLiQingZhao
end
end
object Button1: TButton
Left = 12
Top = 80
Width = 75
Height = 25
Action = actGuCheng
TabOrder = 1
end
object Button2: TButton
Left = 116
Top = 80
Width = 75
Height = 25
Action = actXiMuRong
TabOrder = 2
end
object Button3: TButton
Left = 12
Top = 112
Width = 75
Height = 25
Action = actSuShi
TabOrder = 3
end
object Button4: TButton
Left = 116
Top = 112
Width = 75
Height = 25
Action = actLiQingZhao
TabOrder = 4
end
object cbDisableLiQingZhao: TCheckBox
Left = 232
Top = 116
Width = 81
Height = 17
Action = actDisableLiQingZhao
TabOrder = 5
end
object cbHideLiQingZhao: TCheckBox
Left = 328
Top = 116
Width = 81
Height = 17
Action = actHideLiQingZhao
TabOrder = 6
end
object MainMenu: TMainMenu
Images = ImageList
Left = 332
Top = 4
object N1: TMenuItem
Caption = '现代情怀'
object N2: TMenuItem
Action = actGuCheng
end
object N3: TMenuItem
Action = actXiMuRong
end
end
object N4: TMenuItem
Caption = '古典风范'
object N5: TMenuItem
Action = actSuShi
end
object N6: TMenuItem
Action = actLiQingZhao
end
end
end
object ActionList: TActionList
Images = ImageList
Left = 360
Top = 4
object actGuCheng: TAction
Category = '现代情怀'
Caption = '顾城'
ImageIndex = 0
ShortCut = 16455
OnExecute = actGuChengExecute
end
object actXiMuRong: TAction
Category = '现代情怀'
Caption = '席慕容'
ImageIndex = 1
ShortCut = 16472
OnExecute = actXiMuRongExecute
end
object actSuShi: TAction
Category = '古典风范'
Caption = '苏轼'
ImageIndex = 2
ShortCut = 16467
OnExecute = actSuShiExecute
end
object actLiQingZhao: TAction
Category = '古典风范'
Caption = '李清照'
ImageIndex = 3
ShortCut = 16460
OnExecute = actLiQingZhaoExecute
end
object actDisableLiQingZhao: TAction
Category = '控制'
Caption = '禁止李清照'
OnExecute = actDisableLiQingZhaoExecute
end
object actHideLiQingZhao: TAction
Category = '控制'
Caption = '隐藏李清照'
OnExecute = actHideLiQingZhaoExecute
end
end
object ImageList: TImageList
Left = 388
Top = 4
end
end

此程序运行之后,你可以通过菜单、工具条、按钮和快捷键调出你喜欢的诗句。Action的标题和图标都自动反映在菜单、工具条和按钮上,细心的朋友会发现,菜单上还同时将我们定义的快捷键显示出来,可见VCL的开发者所做的工作比我们想象的还要多。至于菜单名后的热键字符,是由MainMenu的AutoHotKeys属性引起的。
你可以用选择框禁止或隐藏李清照的名字,不过只隐藏李清照的名字时,仍然可通过Ctrl+L调出她的诗句。
休息一下,在我们开始讨论运行时更改软件界面的话题之前,先来感受以下诗人们的情怀。诗人们的诗句是美丽的,但诗句中隐含的哲理才是他们内心所追求的境界。编写程序也是如此。

悟透delphi 第十章 操作界面与操作逻辑相关推荐

  1. 悟透delphi 第十章 操作界面与操作逻辑

    本书原著李战(leadzen)大牛,由tingsking18整理,本人blog发布的版本经过战哥同意,转载请著名出处和原作者!第十章 操作界面与操作逻辑 我们在前面的曾经讨论过,用户界面与商业逻辑分离 ...

  2. 悟透delphi 第二章 DELPHI与WIN32时空

    第一章  DELPHI的原子世界 第二章  DELPHI与WIN32时空 第三章  多线程 第四章  接口 第五章  包 第六章  事件与消息 第七章  组织你的模块 第八章  探索数据库 第九章  ...

  3. 悟透delphi 第二章 DELPHI与WIN32时空

    我的老父亲看着地上玩玩具的小孙子,然后对我说:"这孩子和小时的你一样,喜欢把东西拆开,看过究竟才罢手".想想我小时侯,经常将玩具车.小闹钟.音乐盒,等等,拆得一塌糊涂,常常被母亲训 ...

  4. 悟透delphi 第五章 包

    第五章包 我们在日常生活中会用到各式各样的包,钱包.公文包.背包.书包--,包里面都装有经常要用的东西.一旦你那天要出门远行,带上该带的包就可以了.不用再考虑包里面具体的东西,尽管包里有的东西用得着而 ...

  5. [转]李战大师-悟透delphi 第九章 多层体系结构

    大师当年未完成,占位:) 转载于:https://www.cnblogs.com/yjmyzz/archive/2009/12/15/1624725.html

  6. 悟透delphi 第十一章 面向对象数据库基础

    第十一章 面向对象数据库基础 第二节数据对象的标识 我们在关系数据库的设计和开发中,可能经常需要一些唯一的编号或标识,用来作为关键字,以区别每一个不同的人,每一张不同的单据,每一次不同的信息登记,等等 ...

  7. 悟透JavaScript 1

    编程世界里只存在两种基本元素,一个是数据,一个是代码.编程世界就是在数据和代码千丝万缕的纠缠中呈现出无限的生机和活力. 数据天生就是文静的,总想保持自己固有的本色:而代码却天生活泼,总想改变这个世界. ...

  8. 悟透 JavaScript

    为什么80%的码农都做不了架构师?>>>    悟透 JavaScript Posted on 2008-02-25 13:32 李战 引子 编程世界里只存在两种基本元素,一个是数据 ...

  9. 李战:悟透JavaScript 【转】

    多年前,曾经看过李战大师的"悟透delphi-delphi的原子世界",一直对大师特有的文笔风格记忆犹新,今天无意又看到了大师的"李战:悟透JavaScript" ...

最新文章

  1. Django详解之models操作
  2. 曲线运动与万有引力公式_高考物理曲线运动万有引力专题讲解
  3. 如何将catia装配件附材料_在网上买的快餐桌椅如何安装?餐厅快餐桌椅安装顺序与流程知识...
  4. BZOJ.4553.[HEOI2016TJOI2016]序列(DP 树状数组套线段树/二维线段树(MLE) 动态开点)
  5. 阿里巴巴Java开发手册-日志规约
  6. c语言malloc和直接声明,问下关于malloc的声明问题
  7. jstack会导致JVM停顿
  8. 3款简单实用的在线PCR引物设计软件
  9. 心理测量学信度计算机试题,心理测量学试题及答案
  10. OutMan——Objective-C中成员变量的作用域、@property和@synthesize介绍和使用、构造方法和自定义构造方法
  11. 数据分析与挖掘建模(理论知识)
  12. 如何查看2020最新版谷歌地球高精度卫星地图(附下载方法)
  13. 4.3 jmu-Java-03面向对象-06-继承覆盖综合练习-Person、Student、Employee、Company**
  14. 12:计算2的N次方
  15. css3实现3d效果的立方体动画
  16. 浅谈 js 面向对象
  17. 【Python】批量修改照片日期
  18. AsyncTask的优缺点
  19. App 瘦身最佳实践
  20. System.Data.OleDb.OleDbException: 至少一个参数没有被指定值。

热门文章

  1. 剑指offer(C++)-JZ34:二叉树中和为某一值的路径(二)(数据结构-树)
  2. mysql语句错误怎么查找_SQL语法错误但是怎么也找不出来,求指导
  3. python2 字符串函数_笔记六:python2字符串运算与函数
  4. 计算机程序编辑的英语,编译程序是为把高级语言书写的计算机程序翻译成面向计算机的目标程序而使用的计算机程序...
  5. 多个物体轮廓c语言提取算法,C++ opencv-3.4.1 提取不规则物体的轮廓
  6. java发送qq消息_Java点餐系统和点餐小程序新加微信消息推送功能
  7. Android中如何实现多个框,在android中的对话框中设置多个文本框
  8. linux telnet无法连接,奇怪的问题:telnet无法连接另一台server的正常的开放端口
  9. php自动跳转函数,迅睿CMS 重写控制网站自动跳转函数
  10. Simulink中Simscape—Fluids模块(原Simhydraulics)学习记录