在上篇随笔《脊柱外科病人资料管理系统的界面设计分析》中介绍了一些常用的界面设计方面的内容,本篇继续上一篇,介绍脊柱外科病人管理系统的JOA评分记录模块的界面设计以及实现方面的内容。

JOA(全称 Japanese Orthopaedic Association Scores for Assessment of Cervical Myelopathy),日本骨科学会(JOA)颈椎病疗效评定标准,用于在脊柱外科的术前术后,对患者身体状况进行量化,并制定相关的护理方案提供依据。JOA评分记录模块,是软件《脊柱外科病人资料管理系统》的一个亮点,能使外科医生或者护士,对患者的信息进行全面的记录和研究参考。

1、JOA评分记录模块的分析

JOA评分记录,有点类似于考题的方式,对各项内容进行分值的评估,每项记录的得分不同,汇总成一个总的得分,用于量化评估,它的分类大致如下所示。

从上面的文档截图可以看到,评分项目可以分为一个大类(如自觉症状),多个子项目(如下腰痛)这样的组织方式,然后我们需要记录每项的得分,以及所有项目累加的总分。

通过分拆,我们可以把一个记分的题目作为一个控件,每个题目它自己的得分明细可以动态从数据库获取即可,界面控件设计如下所示。

通过上面的分析,我们知道,一个项目大类(如自觉症状)包含了多个子项目(如下腰痛、步态等)这样的题目,也就是多个上面控件的实例,那么我们设计的项目大类控件界面如下所示。

以上的界面,其实就是在一个大的项目大类控件上组合多个子项目控件的效果。

然后,整个JOA评分的界面就是多个上面项目大类的组合了,组合成了一个JOA评分记录模块的控件效果,如下所示。

最后,我们在第一个文档截图里面看到,JOA评分分为两个方面,一个是术前的,一个是术后的,他们的评分界面完全一样,那么我们可以把它们用两个Tab界面进行分开处理,最后得到的运行界面如下所示。

2、JOA评分记录的逻辑实现

为了在界面呈现各项分数项目,我们需要在数据库设计一个表JOAItem,用来存储每个评分项目的内容,然后在界面中根据分类进行动态展示。

然后定义一个评分子项目的信息对象ControlItem,作为上面控件的信息对象,方便控件和数据库关联起来,记分或者存储明细到数据库中,代码如下所示。

    /// <summary>
/// JOA评分项目明细
/// </summary>
[DataContract]
public class ControlItem
{
/// <summary>
/// 序号,从1开始
/// </summary>
[DataMember]
public virtual int Seq { get; set; } /// <summary>
/// 分类名称
/// </summary>
[DataMember]
public virtual string Category { get; set; } /// <summary>
/// 项目明细列表(包括项目得分等信息)
/// </summary>
[DataMember]
public virtual List<JOAItemInfo> ItemList { get; set; } /// <summary>
/// 评分项目第一项得分(默认得分)
/// </summary>
public virtual decimal DefaultScore
{
get
{
if (ItemList == null || ItemList.Count == )
{
return 0M;
}
else
{
return ItemList[].Score;
}
}
} /// <summary>
/// 默认构造函数
/// </summary>
public ControlItem()
{
ItemList = new List<JOAItemInfo>();
} /// <summary>
/// 参数构造函数
/// </summary>
/// <param name="seq">序号</param>
/// <param name="category">分类名称</param>
/// <param name="itemList">项目明细列表</param>
public ControlItem(int seq, string category, List<JOAItemInfo> itemList) : this()
{
this.Seq = seq;
this.Category = category;
this.ItemList = itemList;
}
}

在上面的评分控件中,我们整合以上的信息对象作为一个整体,部分代码如下所示。

    public partial class ScoreItemControl : DevExpress.XtraEditors.XtraUserControl
{
/// <summary>
/// 单项的序号,从1开始
/// </summary>
public int Seq = ; /// <summary>
/// 控件绑定的信息
/// </summary>
public ControlItem ControlItem { get;set; } /// <summary>
/// 单项的得分
/// </summary>
public decimal Score { get; set; } /// <summary>
/// 处理分数变化后的事件触发
/// </summary>
public event ScoreChangedHandler OnScoreChanged; ............................

当我们在评分控件中指定了ControlItem信息后,在控件的Load事件里面,将会动态绑定评分的项目明细,代码如下所示。

        private void ScoreItemControl_Load(object sender, EventArgs e)
{
if (ControlItem != null && !this.DesignMode)
{
this.lblItemIndex.Text = ControlItem.Seq.ToString();
this.layoutItem.Text = ControlItem.Category; List<CListItem> itemList = new List<CListItem>();
foreach (JOAItemInfo info in ControlItem.ItemList)
{
itemList.Add(new CListItem(info.ItemDetail, info.Score.ToString()));
} radItemGroup.BindDictItems(itemList);
} if (radItemGroup.Properties.Items.Count > )
{
this.radItemGroup.SelectedIndex = ;
}
}

除了ControlItem信息对象的绑定,我们还注意到上面的OnScoreChanged事件,它就是为了我们在整个控件中实现分数动态变化的一个事件,这样我们变化任何一个评分项目信息,单项分数和总分都会重新计算一次的事件。

        /// <summary>
/// 处理分数变化后的事件触发
/// </summary>
public virtual void ProcessScoreChanged(int seq, decimal score)
{
if (OnScoreChanged != null)
{
OnScoreChanged(seq, score);
}
} private void radItemGroup_SelectedIndexChanged(object sender, EventArgs e)
{
this.lblItemScore.Text = string.Format("得分({0})分", this.radItemGroup.EditValue); decimal result = ;
if (decimal.TryParse(this.radItemGroup.EditValue.ToString(), out result))
{
this.Score = result;
ProcessScoreChanged(Seq, result);
}
}

以上代码逻辑就是最小评分控件的一个具体的实现,完成以上这些,还需要完成一个评分项目大类的具体逻辑,它的操作方式和上面差不多,也是引入一个信息对象集合作为背后得分计算的逻辑。

定义的信息对象ProjectItem代码如下所示。

   /// <summary>
/// JOA评分项目信息
/// </summary>
[DataContract]
public class ProjectItem
{
/// <summary>
/// 序号,从1开始
/// </summary>
[DataMember]
public virtual int Seq { get; set; } /// <summary>
/// 项目名称
/// </summary>
[DataMember]
public virtual string Project { get; set; } /// <summary>
/// 项目明细列表
/// </summary>
[DataMember]
public virtual List<ControlItem> ItemList { get; set; } /// <summary>
/// 默认构造函数
/// </summary>
public ProjectItem()
{
ItemList = new List<ControlItem>();
} /// <summary>
/// 评分项目第一项得分总和(默认得分)
/// </summary>
public virtual decimal DefaultScore
{
get
{
if (ItemList == null || ItemList.Count == )
{
return 0M;
}
else
{
decimal total = 0M;
foreach (ControlItem item in ItemList)
{
total += item.DefaultScore;
}
return total;
}
}
} /// <summary>
/// 参数化构造函数
/// </summary>
/// <param name="seq"></param>
/// <param name="project"></param>
/// <param name="itemList"></param>
public ProjectItem(int seq, string project, List<ControlItem> itemList) : this()
{
this.Seq = seq;
this.Project = project;
this.ItemList = itemList;
}
}

然后该控件的逻辑代码就是结合这个信息对象以及控件的一些事件进行处理了,控件的部分代码如下所示。

    public partial class ScoreProjectControl : DevExpress.XtraEditors.XtraUserControl
{
/// <summary>
/// 项目大类的序号,从1开始
/// </summary>
public int ProjectSeq = ; /// <summary>
/// 项目大类的信息
/// </summary>
public ProjectItem ProjectItem { get; set; } /// <summary>
/// 处理分数变化后的事件触发
/// </summary>
public event ScoreChangedHandler OnScoreChanged; private Dictionary<int, decimal> scoreList = new Dictionary<int, decimal>();//记录单项的得分列表 ...................

由于每项评分子项目是单独的评分控件,控件的布局采用了FlowLayout布局呈现方式,因此在控件的Load事件代码如下所示。

        private void ScoreProjectControl_Load(object sender, EventArgs e)
{
if (ProjectItem != null && !this.DesignMode)
{
this.lblProject.Text = string.Format("{0}、{1}", ProjectItem.Seq, ProjectItem.Project); this.flowLayoutPanel1.Controls.Clear();
int index = ;
foreach (ControlItem item in ProjectItem.ItemList)
{
ScoreItemControl control = new ScoreItemControl();
control.ControlItem = item;
control.Seq = index++;
control.OnScoreChanged += new ScoreChangedHandler(control_OnScoreChanged);
this.flowLayoutPanel1.Controls.Add(control);
}
}
}

同样整个控件也有一个OnScoreChanged 的事件,我们看到,这个和上面介绍的事件操作方式类似,都是一级负责一级的分数处理,具体代码如下所示。

        void control_OnScoreChanged(int seq, decimal score)
{
if(!scoreList.ContainsKey(seq))
{
scoreList.Add(seq, score);
}
else
{
scoreList[seq] = score;
} //项目的总分变化
ProcessScoreChanged(ProjectSeq, this.TotalScores);
}

以上的控件实现逻辑一步步递推,就能很好实现评分项目的动态呈现,以及控件评分分数的动态变化和总分记录保存,由于涉及的实现细节还比较多,一篇随笔介绍内容太多显得累赘,但是其他控件的实现逻辑和上面的操作方式差不多,在这里就不在一一赘述了,本文主要提供一个这种的实现思路进行JOA评分记录模块的实现,进一步拓展,可以把它应用到考试题目上 ,可以作为动态抽取题目,然后记录测试者的题目选择信息,最后把测试者的答案和标准答案对比得出用户的总分,这样就完成了试题的动态测试案例了。

脊柱外科病人资料管理系统的界面设计分析(2)--JOA评分记录的实现的更多相关文章

  1. HTML5+规范:nativeUI(管理系统原生界面)

    nativeUI管理系统原生界面,可用于弹出系统原生提示对话框窗口.时间日期选择对话框.等待对话框等. 1.方法 1.1.actionSheet: 弹出系统选择按钮框 void plus.native ...

  2. WPF软件开发系统之四——医疗病人信息管理系统

    仿360悬浮窗的方式,始终有个工具栏浮在桌面的最顶层,方便任何时候操作. 主要功能包括:病人信息的添加.修改.查询.包括别人基本信息.诊断结果.接待医生.手术多张图片等. 系统特点:简洁.易操作.美观 ...

  3. Qt编写气体安全管理系统(界面超漂亮)

    自从把Qt样式表葵花宝典这个pdf文件看完以后,将所有的qss内容都轮了一遍,还写了个皮肤生成器工具,https://blog.csdn.net/feiyangqingyun/article/deta ...

  4. 在EF的code frist下写稳健的权限管理系统:界面设计(四)

    基本都是采用pure设计(中文官网:http://purecss.org,英文官网:http://purecss.io).pure只是一个简单强大的cssUI库,支持响应式设计,适合自己设计或者给美工 ...

  5. 黑色的网站后台管理系统ui界面——后台

    链接:http://pan.baidu.com/s/1pLffwE3 密码:m4v6

  6. Docker集中化web界面管理平台-Shipyard部署记录

    Docker图形页面管理工具基本常用的有三种: DOCKER UI,Shipyard,Portainer.对比后发现,Shipyard最强大,其次是Portainer,最后是Docker ui.之前介 ...

  7. Django项目:CRM(客户关系管理系统)--68--58PerfectCRM实现king_admin批量生成上课记录

    # kingadmin.py # ————————04PerfectCRM实现King_admin注册功能———————— from crm import models #print("ki ...

  8. Django项目:CRM(客户关系管理系统)--67--57PerfectCRM实现admin批量生成上课记录

    #admin.py # ————————01PerfectCRM基本配置ADMIN———————— from django.contrib import admin # Register your m ...

  9. Winform开发框架之通用高级查询模块

    最近一直忙于公司的事情,虽然一直在做一些相关的技术研究,但是很久没能静下心来好好写写博客文章了,想想也有半个月之多了,这半个月来,也一直致力于改善我的WInform开发框架,使得自己及客户使用起来更加 ...

随机推荐

  1. ubuntu下取代ping的好工具tcpping

    $ sudo apt-get install tcptraceroute bc$ cd /usr/bin$ sudo wget http://www.vdberg.org/~richard/tcppi ...

  2. adding validation annotators to model classes 在linq to EntityFrame的Model中添加前台验证validation annotators

    The same solution can be applied for LINQ to SQL. The snippet the article shows for using the Metada ...

  3. JavaScript跨域方法

    一.什么是跨域 JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象.但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦.这里把涉及到跨域的一些问题简单地整理一下: ...

  4. Oracle-ARCGIS-SDE 数据整合遇到的问题

    一. 近日在做全文检索,基础采用oracle text,版本是10g,做好管理页面后,有功能是删除索引,就是生成drop index的语句.没有想到这个全文检索的index这么直接弄还不行,经过这样删 ...

  5. Versions 出现 SVN Working Copy xxx locked

    Versions处于选中状态,Finder的导航栏就是Versions的导航栏,如下图,Action - Cleanup...,就可以解锁了

  6. 验证 Xcode 是否来自正规渠道

    由于最近的 Xcode Ghost 事件的发生,所以我们有必要在安装完 Xcode 时验证其是否来自正规渠道.   在终端系统上运行以下命令启用检测: spctl --assess --verbose ...

  7. POJ 2082 Terrible Sets

    Terrible Sets Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 2747   Accepted: 1389 Des ...

  8. 30分钟入门Java8之默认方法和静态接口方法

    30分钟入门Java8之默认方法和静态接口方法 前言 上一篇文章30分钟入门Java8之lambda表达式,我们学习了lambda表达式.现在继续Java8新语言特性的学习,今天,我们要学习的是默认方 ...

  9. js深拷贝和浅拷贝

    一.数组的深浅拷贝 在使用JavaScript对数组进行操作的时候,我们经常需要将数组进行备份,事实证明如果只是简单的将它赋予其他变量,那么我们只要更改其中的任何一个,然后其他的也会跟着改变,这就导致 ...

  10. 【Java】深入理解ThreadLocal

    一.前言 要理解ThreadLocal,首先必须理解线程安全.线程可以看做是一个具有一定独立功能的处理过程,它是比进程更细度的单位.当程序以单线程运行的时候,我们不需要考虑线程安全.然而当一个进程中包 ...