Murphy
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


User Interface States control

我一直从事代码的编写和软件架构设计,发现大家对需求分析,软件管理,程序的架构设计,数据库设计,性能和安全等非常的重视。而且有不少经典成熟的技术可以使用,例如我个人非常喜欢《人月神话》,《敏捷软件设计》,《软件工程开发与实践》,《软件设计模式》等。通过软件设计人员和行业专家的努力,在项目开始阶段,都会存在一个架构清晰,业务相对明确,(可能以后会有变动),并且附带一份分工明确和明确Deadline的项目计划(虽然很多Deadline都被迫越来越符合商业合同,而不符合项目开发周期的规律)。然而我们却忽略了编码中最耗费时间和最容易出现Bug的地方,那就是界面设计和编码工作,而这里的工作也是最让一些软件设计人员所不齿,大多数人认为一个刚刚工作的大学生就可以完成的很好。实际我们存在这种观点的主要原因是:认为这方面的工作不存在太多的技术含量或者不需要太多的技术经验积累,一个刚毕业的大学生和工作多年的程序员做这份工作结果没有什么本质区别。真得是这样吗?答案是否定的,除了编码技术的熟悉程度之外,其实这里存在相应的方法学。善于总结分析得软件工程师都会有类似的处理方式。如果处理得当,将会大大提高程序的健壮性和可靠性,易于维护,并且可能会发现在模块设计和需求分析中的错误和弊端,在开始编码的时候就可以纠正。本文将详细阐述这些方法。

第一部分:界面状态控制

为什么需要状态

我一般认为界面都是由以下三个要素组成的:属性,命令和状态。这三方面存在既相互独立,又相互联系。在我们编写代码的时候,往往比较注意的是属性和命令这两方面,而忽视状态的存在。为什么会这样,因为属性和命令都很直观,属性就是界面各个控件的属性状态和内存中的数据值,而命令几乎就是模块功能,或直观的就是界面上的各种控件,例如:按钮,菜单等等。但是当我们点击按钮完成命令,并且属性更改成功后,我们会发现现在界面停留了下来,保持了一种静止状态,在等待下一个命令的开始。仔细的思考,命令的作用就是使计算机计算存储后把最终的结果返回给使用者,而这种静止状态就是计算后得结果。并且结果的种类或叫做界面上的静止状态是有限个数,并且循环不断的发生。提到界面状态有一点抽象,但呈现给使用者的是存在的界面属性,并且跨越了一个时间段。

我们使用系统的目的是得到结果,就是状态,所有用户的命令(按钮事件等),和属性的改变都是为了这个目的而进行。所以我认为界面是状态驱动的,确切的说是状态变化驱动的。就好像说,我要达到什么目的,所以我要做什么(命令),使什么(属性)改变。这还是有点抽象,但不要紧,等你习惯这种思考问题的方式时,很多混乱想法都会变得清晰。

关系

研究关系总是比研究实际存在的单体事物要复杂的多,但在这里,我们确认界面是状态驱动的后就变得简单了。属性和状态是被动静止的。更改状态都是从动作开始,而状态的更改导致属性的更改,同时状态改变完成可能需要自动到达另外一个状态,就需要使用动作来完成。如下图所示。

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

第二部分:属性

什么是属性

我们可以把属性理解为程序中随命令和状态改变而改变,并可划分到某个特定状态中去的内存中的变量值,也就是属性。因为界面上的可视状态也是内存变量值。如果你需要和普通的类中的属性区分开,我们就加一个前缀,叫界面属性。而那些与命令无关的可视状态和内存变量不属于此范畴。例如:界面上的时钟,它是随着时间变化的,和命令无关,也不属于任何状态。

属性分类

属性或界面属性在作用上可以划分为可视的状态和业务数据值两类。

可视状态:是用来方便用户操作,提高用户使用效率。包括界面控件的颜色,可编辑性,可见性等。有些界面可能需要控制焦点状态,鼠标位置,窗口位置和大小等。

业务数据值:主要是用来展现数据内容和计算结果的。就是指保存在内存中或界面控件上的数据的状况,例如在在列表数据中,如果是编辑状态,需要在编辑行的客户名称列中,显示所有客户名称,以便操作者来改变这条记录的客户属性。

使用属性

设计归纳这些状态是很重要的,我想一般通过软件的设计文档,界面Demo,结合开发经验和用户使用习惯基本上就可以确定。如果有必要,可以和软件设计人员等交流来确定这些界面属性,并且可以与下面将要提到的动作和状态来构成一个表格。

界面上的控件不宜过多,如果达到一定的数量,程序的复杂度和难易度会随之上升,并且需要更长的时间来培训客户。

第三部分:命令

什么是命令

命令一般就是系统的功能的代名词,但系统为了提高系统的可使用性,一般还会添加一下对系统的功能的补充功能,来完善命令体系,使系统更完整和更加易于操作。

命令组成

传统的做法我们一般把业务系统命令分成如下几个步骤来完成,并且具有一定的顺序性。我在编写代码的时候很喜欢把这些步骤单独分出去作为单独的函数,根据不同的命令来进行不同的处理。例如数据校验,我们独立出一个数据校验方法,我们要做的就是区分开根据是删除的,是添加的,还是修改的等命令。但他们大部分的过程都是可以重用的,所以独立成一个方法,甚至一个类处理都是不为过的。同样的事情发生在数据采集,调用业务接口,更改页面属性等等。但我们在调用这些函数的时候,需要区分不同的命令,如果这个函数只有两个命令来调用,我们可以简单的添加上一个bool变量来区分,但如果调用者过多,我们不得不使用枚举或常量等方式来判断。这些函数都有可能会用到。在命令的开始,如果我们就能够清楚地了解这些枚举值,在调用这些共享方法时就会简单得多。这就是我最开始意识到状态之所以存在的原因。

软件中的很多技术和知识都来自于实际工作当中。我们不断地发现,思考,总结。如果正确,与那些和你有同样的想法的人交流经验,并广为传播。大多数成功的软件技术都是来自于集体的思考和类似开源的思想。以上是一些题外话。

下达命令

功能以函数的形式存在于程序中,调用这些函数就需要程序的使用者通过界面上的按钮或菜单来完成。有些时候系统也会自动去调用这些函数,例如:word中的自动保存功能,或为了达到一致性,系统会在一定频率下自动获取数据,或者服务端系统获得数据库的更改来通知客户端来获得最新的数据。这些调用的完成我们都是通过事件来完成的。

同样一个命令或者函数,我们都有可能对应很多不同的事件。如下图所示。他们的目的相同,对于命令函数来说唯一可能不同的是不同事件发生后,完成命令所需的参数有所不同。

上面这张图是比较常见的一种事件与命令之间多对一的关系。当然也存在同一个事件会调用不同的命令。但我们会根据既有的条件来判断调用哪个命令,所以上图可以改为有条件的事件与命令之间的关系。

虽然这种事件命令之间的关系直接而且简单,但对于我们之后讨论得到的状态改变事件调用命令,显得更加完整和易于使用。这样不但使系统具有更好的藕和性,而且从命令开始到命令结束我们都清楚知道系统所处的状态。

第四部分:状态

在我们开始一个界面或者模块开发的时候,都会从软件设计师或项目经理那里得到一份模块功能设计,模块需求描述和ER模型图,并且会从美工那里得到一份界面样式的Demo。如果你认为这些已经足够了,并且开始工作,那我觉得,你可以等等,花一个到两个小时或者更长时间来做一项工作,这主要取决于模块的复杂度和界面元素的数量。那就是根据你所得到的资源来在笔记本画一张界面状态图。

以界面状态为核心,所有界面上的事件,业务接口和界面属性的都是围绕他来进行处理。正确定制状态和清晰的描绘状态之间的转化是非常重要的。这需要更改我们的编程习惯,更确切的说是规范我们的界面编程方式。这对提高编码效率和降低错误率是很重要。

每当讲到这里时,我还是习惯举一个例子来说明如何围绕状态来编程,并且简单的介绍一下我的状态控制引擎。

定义状态

在得到模块设计文档的时候如何定义状态。我这里有个简单的定义,就是任何命令或功能开始到完成之间的过程定义为状态,界面任何时候都存在并且只存在一种状态之中

任何时候界面上只能存在并且只能存在一种状态之中。界面的主要功能就是提供给用户的操作和展示的接口,所以界面上也主要就是展示和操作。所有的操作基本都能够至少完成一个功能,这个在模块设计文档中都会描述。一般的界面都会完成增,删,改,查,四个功能。但这些功能不是直接完成,而是需要时间延迟。例如你要添加一条记录,那需要用户输入相应的数据后点击后才能完成。完成系统要马上调用另外一个命令,进入另外一个状态,例如添加成功后是显示状态。这个过程是连续不断的。到底进入哪个状态是根据界面设计习惯和系统要求决定的。有的系统在添加状态后就是显示状态,而有的系统则是修改状态,不论进入那一种状态,系统都要保持设计一致性。

我们可以从这个定义中得到很多启示,首先我觉得就是任何命令都有开始和结束的事件(或者简单的说是按钮)来对应。有时候,很多人不理解,为什么界面上的“添加”不是直接保存到数据库,而是仅仅让一些TextBox控件变成可编辑。点击“保存”才是真正的保存操作。因为你需要与用户交互,得到用户的输入信息,自然而然的就存在状态的思想,点击添加来确定开始这个状态,点击保存来结束这个状态。有的时候我们没有更好的提示,来告诉用户怎样来开始这个状态,就只好把“添加”按钮来充当这个角色。如果我们确认界面状态的思想,我们完全可以使用“开始添加”按钮,来更确切的告诉用户,系统需要你来做什么。也不会存在保存按钮来完成两种或者更多的功能,例如“保存更改”和“保存添加”,甚至更多。

我们还可以确定一个事情,就是命令的持续性和状态的持续性。而事件是改变状态的动力也是一个命令的开始。完成一个命令,就马上要开始另外一个命令,引起另外一个事件。转化到另外一个状态。所以他们就像闭合环路状态图。

分析状态和状态转化

我们首先看一个普通应用程序界面:

这是一个非常普通的应用程序界面,不论是B/S的还是C/S的,我们都会有这样类似功能的界面。让我们根据这个页面来一步一步分析界面上的状态和状态转化。

首先我们会知道这界面的几个主要功能:添加,删除,修改,显示。我们可以把它当作系统功能,或者简单的叫做命令。我们所要证明的就是一个命令的结束就是另外一个命令的开始。根据系统需求和用户使用习惯,我们可以得到以下命令转化关系。

但是为了提高用户交互的友好性,我们会引入另外两个功能,就是保存和取消,来完善我们界面功能。最终得到以下的命令流转图。

其实我们界面上能够完成这几个命令的方式有很多种,例如:在选中DataGrid的某一行,双击时会调用修改命令,在进入这个界面的时候会调用显示命令,在离开这个界面的时候会调用添加或修改命令,或者在按钮除外还存在一个ContextMenu等等,但是他们能完成的功能就只有这些,即一些关键值,例如当前记录的ID的不同而已。每个命令都不是马上完成的,有的需要与用户交互,有的时候会等待服务器调用时的延迟。在该过程中都会存在一个没有调用任何命令的“静止”状态。这时候我们就会发现一个添加命令会在时间上有所延迟,而线段的两个端点就是开始这个命令的事件和结束这个命令的事件,中间就是状态。

于是我们会得到如下的图示。

这个时候“添加”并不是命令,而只是命令的开始,保存便是去完成这个命令,中间浅绿色线段便是我们需要得到的状态。但是我们会发现从添加开始会有两个线段,其实他们都是处于一种状态之中,就像下面的图示一样。而他们的区别往往是取决于开始事件的状态数。如果只有一根,就像添加事件,他只有从显示开始,那么这两个线段的处理是一样的。而如果像显示事件,它之前存在很多状态,那么在这个状态时可能就要对得到关键数据,例如记录的ID或Index值和之前的状态,来进行一些差别处理。

根据上面的图,我们又自然而然的得到了如下所示的状态转化图。

如果你觉得其中的两个相邻的状态没有任何差别,或者其中一个状态什么也没改变,那你就可以合并其中的两个状态。但合并过程中,建议在将相邻的两个状态合并后再考虑是否还需要再次合并。在我的一些Demo中,“取消状态”没有给出提示框,例如“是否确定放弃更改?”的提示。那么就可以和后面的显示状态合并。最终的结构就是下图。

每少一状态,就会相应地少了与状态相联的状态数目根线,同样添加一个状态,就会增加这么多根线。界面的复杂性也就体现在这里,简单的说是状态多少,而最根本的原因则是状态之间转化关系的复杂性。我没有给出工作量(人日)与其中的关系,但可以确定的是它们是成正比的。但不一定与代码量成正比,如果我把状态放开,考虑系统的稳定性和健壮性再添加几个状态进去,你会发现代码的增加并不是很多,但工作量提高了,就是因为工作的复杂度提高了。

但是如果你在完成以上步骤后,就可以规划自己的程序,和开始放心的编码了。如果这个时候由于客户的新要求或项目经理告诉你界面需要改动时,你就会心里有底,知道哪里需要改,哪里不需要改动。根据状态的变动得到状态关系转化的变动,便可以得到改动的大概时间和难易度。我认为这可以作为一个尺度来评定一些我们界面上无法量化的东西。

在整个分析过程中,这个界面只需要一个小时,而复杂一点的界面也可能最多只需要一天到两天的时间。在余下的整个开发过程都可以按照他来做,减少了开发过程中思考的时间,并且使系统不是围绕事件来处理,而是按照一种更科学的方式来进行。正是状态隔离了事件和属性,业务接口之间的关系,才使得系统更加易于理解和分析。

界面复杂度和工作量

我们知道界面只是模块中的一个组成部分,例如就像分层一样,我们一般会分为,表示层,业务外观层和数据访问层。各个层的复杂度度量方式都不尽相同。例如业务外观层主要取决于业务之间的复杂度和系统架构的复杂度。例如你需要面向服务的Webservice来包装业务外观。而数据访问层的复杂度在于OR转化,SQL自动化生成,异构数据库地能力。?而界面的复杂度的度量主要来自界面的状态数目和状态转化的复杂度。

在编写界面代码时,最安全的方式是在每次状态转化时都要把所有界面属性重新赋值,即使上一个状态的此状态的很多属性都相同。这样做对于需求频繁变化和界面控件数量还没有完全确定的情况下尤其重要,这样只会少犯错误。但状态数目越多,那么你的代码就越多,而且可能会成倍增加,从而导致界面的工作量的上升。

在状态转化时,我们需要大量的数据来完成逻辑判断或方法调用。一般情况下状态转化越复杂,那么判断这些数据变量的赋值就越复杂。导致程序在考虑他们的关系时需要花费更多的时间,而且测试的时间也会随之增长。

第五部分:状态控制机

设计

在得到状态和转化关系后,我们就需要来围绕它使用。把状态控制机制应用到系统当中。下面我就根据我所编写的状态控制机引擎(Murphy beta 1.0)来介绍一下如何完成一个适合你自己系统的状态机引擎。并且怎样在系统中嵌入这个引擎。

我认为一个完整的状态控制引擎至少需要状态和状态转化的定义,状态控制?(我认为这里不够清楚)两个方面。状态定义,我认为可以把XML或者类作为最终的数据倒入形式。并存在一个Loader的机制来完成从定义在XML,数据库,或传输过来的二进制文件转化为你所需要的形式。我使用的State类和StateTransfer类作为最终的倒入形式。这样既可以将编码方式存于dll中也可以通过loader来把他装载。

如上图所示,State类为状态类,它包含了状态的定义,其中你会发现Method属性,主要是他在状态转化为此种状态时,状态引擎自动来需要调用的方法,在XML中你也发现这个字段,可以为空。

StateTransfer类为状态转化规则类,它包含开始状态和结束状态。

StateTransfers类和States类为状态转化规则集和状态集类,它们会带有一定的验证功能,包括重复性和数据正确性。

StateLoader类为把其他形式存储的状态和状态规则数据读入到内存中。我提供了一个默认的把XML读入的接口方法。并规定XML定义规范。

<?xml version="1.0" encoding="utf-8" ?>

<MurphyState>

<States>

<State>Display</State>

<ChangedMethod>On_Display</ChangedMethod>

</States>

<StateTransfer>

<BeginState>Delete</BeginState>

<EndState>Display</EndState>

</StateTransfer>

</MurphyState>

此XML借用了XSD样式,这样就可以轻易的被DataSet类读入而不需要Xml读取。在规则转化定义中为了尽量少的数据的存在,而只规定了状态转化中需要控制的转化关系。为了能够说明这点,我把应该在状态引擎的部分转化原理提前在这里描述一下。

例如:如果你的程序在转化时的上一个状态为“Add”,希望转化到Display状态。系统会找开始状态为“Add”和转化规则,和结束状态为“Display”的转化规则。如果一条也没有找到,则表示不做规范,可以转化。如果找到了一条或更多条转化规则,则需要从中寻找对应的结束或开始状态是否存在“Display”或“Add”,如果有,则可以转化,如一条也没有,则转化失败。

由于在数学知识和项目经验方面的局限性,我无法给出一个最优的定义规则。但我提供了源码,并且这个类可以被继承,也可以在这个类做多态,等等方式。这里留给大家充分的发挥空间。这种方式同样存在于下面将要讲到的状态引擎。

有了以上的准备,我们可以定义StateEngineBase类了,这个类是整个界面状态转化的核心部分。他主要是装载状态和状态规则后,监控界面状态的变化,并且告知界面状态变化后需要做的事情或告知界面状态变化了,而由界面去决定如何做。所以我开放了两种方式。一种是反射机制的,在状态变化时,自动调用系统的方法。还有就是事件机制。但不同编码语言或不同系统环境可能只能提供一种方式。

StateEngineBase类提供了几个属性:CurrentState为当前的状态,LastState为之前的状态,如果是第一次进入系统,则为NullState。States和StateTransfers为状态集和状态转化集属性,Instance属性是为State.Method属性准备的,它提供调用方法类的实例。

StateEngineBase类的SetCurrentState(string stateValue)方法提供界面状态转化的接口。它主要是完成状态转化,状态规则检验,和调用状态转化方法和提供事件输出。

第六部分:实现

不同的实现

虽然程序的种类非常复杂,但我们还是可以简单把界面部分分为单语言单平台实现和多语言多平台实现方式两种。这里的语言是指编程语言,例如:C#,JAVA,JS等等,而平台是指语言的运行环境,例如.NET,JVM,IE等等。简单的就是C/S和B/S结构。但C/S结构的界面也有可能嵌入了多种语言,使用多种技术。例如:.NET开发的界面有可能嵌入VB 开发的COM组件,而且也可以单独完成某项功能。这样多语言多平台就导致了需要共享界面状态,构造同样的状态引擎。

显然多语言多技术平台的实现要比单语言单技术平台更复杂。但我们能够清晰的给出简单的实现方式,而复杂的再添加上之间的调用关系。问题也就不复杂。首先我们先讨论一下简单的实现方式。

如果可以,我希望开发一种可以与各种集成开发环境结合的软件。它们是界面化??的来定义某一个界面的状态和转化规则,并且制定这种状态下的界面组件属性状态,内存业务数据和调用那种业务接口。这样就会大大降低程序员在界面控制的工作量并且更高效。

单语言单平台的实现

在单语言单平台上的实现,根据使用规模,可以分为两类。如果程序的模块繁多,界面复杂。我们可以像我在状态设计章节中所作的一样,单独设计复杂的状态控制引擎,状态和状态转化的读取和控制等等。并把这些相关类放到一个DLL里来抽象出状态控制内容。变成系统架构的一部分,并可以被重用和替换。这是一个比较好的解决方案。但有些程序的规模不是很大,或者界面部分都很简单,只有个别的界面模块比较复杂。那我比较建议仅使用界面状态控制的思想。在界面代码中自定义界面状态和转换规则,并且完成类似状态引擎的工作就可以了。

灵活的设计方式才是软件设计的精髓,就像Nhibernate很好,但对于一个仅有几万行代码的小程序,它就显得太大了。非要给摩托车安装飞机的引擎只会导致系统的不稳定甚至崩溃而且代价太高。如果对于比较简单的界面,你不用界面状态控制也足以较好的完成界面的编码,那就用它好了。技术的产生并不是给软件工程师带来负担,而是要减轻他们的负担。

多语言多平台的实现

这种情况在B/S系统应该是最常见的,我们会发现就像在界面和后台代码中都需要校验一样,界面状态控制同样需要同步进行。同时这也对我们的状态引擎设计工作带来更大的挑战。但这比跨工作流引擎来完成一个工作流要简单得多。他们在很多方面都有相似之处。例如都需要同样的引擎算法,可以共享的通信协议和同步机制。

这部分工作到现在为止还没有开始,但我希望能够得到大家的帮助来完成这部分的内容。

第七部分:扩展

有限状态机理论在软件设计开发上可以大量使用,它不仅存在于界面控制上,还有我们所熟悉的任务流管理上,但任务流过于复杂,它更多的任务是用来完成业务多与任务流转方面的应用,而在一般情况下相对比较简单但却十分重要的,例如:在ERP系统中,各种单据之间的关系和流转却使用有限。我希望能够研究出关于基于业务逻辑可简单嵌入式流程定义控制器。并把状态机理论推广开来,应用于任何相关领域。

结束语

一个控制控件(例如按钮,菜单等)非常多,且需要可控制的界面属性也非常多(例如,Disable,Display,)的界面,常常会使我们会焦头烂额,以致错误百出,最后不得不推倒重来,即使完成,我们也不会满意一个有几百上千行非常混乱的代码的程序。如果这时候项目经理说,由于业务有变动,需要你更改其中一些内容或添加一些新功能的时候,我想你当时的想法一定是,编程工作是如此的枯燥乏味,没有任何的成就感,并且非常担心被测试。作为一个程序员,我们需要来改变这种状态,这也是我所想达到的效果。

这是我第一次尝试撰写一篇文章来完整地阐述我的观点,所以在相关的技术,例如数学,软件设计和开发经验等都有很多的不足,甚至错误,希望大家通过论坛或电子邮件来指正让我们一起探讨并完善它[Hu2] 。在完成这篇文章的过程中几乎没有参考任何资料,因为我还没有找到相关文章。但有可能已经存在,所以如果和任何已经存在的技术或理论所阐述的内容相同,那么这篇文章只是从我的角度来描述,同时也希望各位软件同仁向我推荐。

为什么叫Murphy(土豆),很简单,我喜欢吃土豆,觉得土豆是唯一我不变的爱。平凡但我却离不开它,胜过任何美味,非常的伟大。

转载于:https://www.cnblogs.com/richardhu/archive/2006/07/27/461224.html

UISC-User Interface States Control ;Murphy 用户界面状态控制(Beta)相关推荐

  1. java状态机(订单状态控制)

    一.状态机 状态机是状态模式的一种应用,相当于上下文角色的一个升级版.在工作流或游戏等各种系统中有大量使用,如各种工作流引擎,它几乎是状态机的子集和实现,封装状态的变化规则.状态机可以帮助开发者简化状 ...

  2. 【OpenCV-Python】5.OpenCV的图形用户界面窗口控制

    5.OpenCV的图形用户界面窗口控制 文章目录 前言 一.窗口控制 1.创建窗口 2.关闭窗口 3.调整窗口大小 二.OpenCV-Python读写显示图片固定格式 三.OpenCV-Python资 ...

  3. java 线程 状态 图_Java线程中的生命周期和状态控制图文详解

    这篇文章主要介绍了Java线程的生命周期和状态控制,需要的朋友可以参考下 一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于 ...

  4. 【转】Pro Android学习笔记(二五):用户界面和控制(13):LinearLayout和TableLayout...

    目录(?)[-] 布局Layout 线性布局LinearLayout 表格布局TableLayout 布局Layout Layout是容器,用于对所包含的view进行布局.layout是view的子类 ...

  5. 利用blinker,让arduino实现多路继电器状态控制和APP端状态反馈

    利用blinker,让arduino实现多路继电器状态控制和APP端状态反馈 有需要的朋友可以直接拷贝代码拿来使用,按钮是自锁按钮控制的,不是点动开关型的.这是经过许多人的经验总结和奉献才调通的程序, ...

  6. 解析图腾柱无桥PFC的状态控制(基于DSP C2000)

    解析图腾柱无桥PFC的状态控制(基于DSP C2000) \\\插播一条: 自己在今年整理一套单片机单片机相关论文800余篇 论文制作思维导图 原理图+源代码+开题报告+正文+外文资料 想要的同学私信 ...

  7. 闲人闲谈PS之三十六——项目状态控制

    **惯例闲话:**最近感觉时间不够用,脑子有很多想法,但是到下笔却感觉总是下不了手,写完一段,感觉和自己想的差距很大,然后有全部删除-这难道就是传说中年纪大了,手脚不停使唤-这让闲人更加焦虑了,前篇还 ...

  8. Hover States - 有趣的用户界面及交互设计

    Hover States 一组新潮的和有趣的用户界面和交互设计的集合.Hover States 的目标是要成为设计师和开发人员灵感来源,向人们展示目前人们正在做的各种网站中令人惊奇的效果.他们认为交互 ...

  9. Windows Vista应用程序的开发中,对应UAC(User Account Control, 用户帐户控制)的开发需求 (二)

    How UAC Works          UAC如何工作 This section describes the architectural and functional components of ...

最新文章

  1. POJ 3177 判决素数个数
  2. arduino蓝牙通讯代码_「Arduino」OLED屏使用教程,显示内容听谁的?我不管,听我的...
  3. Flutter开发之ListView组件(21)
  4. android circleimageview 导入到eclipse,android项目从Eclipse迁移到Android studio中常见问题解决方法.pdf...
  5. IPv6网络协议的安全疑云
  6. pyqt5讲解9:时间模块timer和网页交互
  7. 信息学奥赛一本通(1115:直方图)
  8. 启航RPA卓越生态联盟,艺赛旗打造最强RPA产业生态圈...
  9. 解决git rebase操作后推送远端分支不成功的问题
  10. 【每日一linux命令4】常用参数:
  11. 期货反向跟单这个模式、大家目前都耳熟能详,操作原理也算是人尽皆知了!
  12. 大数据可视化:Echarts
  13. 世界语言缩写,各国语言简称,各国域名缩写
  14. macd的python代码同花顺_MACD最全的运用方法!
  15. 计算机软件开发属于什么类的专业,软件工程专业属于哪个类别?
  16. 消息队列(MQ) 企业服务总线(ESB)
  17. python----语句
  18. 腾讯2018第一季度财报:微信用户超10亿,线下零售红利已到来
  19. SpringBoot导出word模板并动态渲染数据
  20. [OHIF-Viewers]医疗数字阅片-医学影像-es6-Element.querySelector()

热门文章

  1. mysql高可用架构介绍_MYSQL高可用架构
  2. 论高校计算机信息管理能力的提升,论高校计算机信息管理能力的提升
  3. nginx 正向代理
  4. TensorFlow tf.keras.layers.conv2D
  5. Sphinx sphinx_rtd_theme
  6. C语言连接PostgreSQL数据库
  7. java验证码技术_java验证码前台技术
  8. 项目安装使用uuid_在uniapp中使用fingerprint2实现游客设备标识
  9. 大型综合体弱电智能化解决方案标书
  10. RVC使用指南(六)-排错