在上篇随笔《脊柱外科病人资料管理系统的界面设计分析》中介绍了一些常用的界面设计方面的内容,本篇继续上一篇,介绍脊柱外科病人管理系统的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. icmp,tcp,traceroute,ping,iptables

    有东莞的监控主机到北京BGP出问题了: 报警短信疯狂发送: 找东莞IDC和北京BGP服务商协查: 有个奇怪的问题:北京到东莞trcaceroute都有路由信息 东莞143段到北京全无路由信息:但,东莞 ...

  2. Android开发(二十七)——android:layout_weight的真实含义

    android:layout_weight的真实含义是:一旦View设置了该属性(假设有效的情况下),那么该 View的宽度等于原有宽度(android:layout_width)加上剩余空间的占比! ...

  3. chrome https添加信任

    在浏览器地址栏输入:chrome://net-internals/#hsts 然后到Add domain下,Domain添上诸如google.com和google.com.hk ,并勾选Include ...

  4. 简单配置nginx使之支持pathinfo

    只需要修改3个地方就可以了 location ~ \.php {    #去掉$ root          H:/PHPServer/WWW; fastcgi_pass   127.0.0.1:90 ...

  5. 【Xamarin报错】AndroidManifest.xml : warning XA0101: @(Content) build action is not supported

    部署xamarin.forms android时报错: Android\Properties\AndroidManifest.xml : warning XA0101: @(Content) buil ...

  6. SQLServer 获得所有表结构(包括表名及字段)

    then d.name else null end) 表名, a.colorder 字段序号,a.name 字段名, ( then '√'else '' end) 标识, (case when (SE ...

  7. Android之TextView文字绘制流程

    一:TextView的onDraw()方法: 1.第一句restartMarqueeIfNeeded()绘制字幕滚动. protected void onDraw(Canvas canvas) { r ...

  8. C#操作FTP报错,远程服务器返回错误:(550)文件不可用(例如,未找到文件,无法访问文件)的解决方法

    最近在做项目的时候需要操作ftp进行文件的上传下载,但在调用using (var response = (FtpWebResponse)FtpWebRequest.GetResponse())的时候总 ...

  9. [原]零基础学习视频解码之seek

    现在,我们要添加一些功能,当你看不能倒带的电影,是不是很烦? 那么函数av_seek_frame功能看起来是多么赏心悦目. 我们将让左,右箭头来回走在影片中通过一个小的向上和向下箭头很多,其中“三多一 ...

  10. c++ 相关的技术资源整理归类

    最近一段时间 c++ 社区里最火热的话题莫过于 cppcon2015 了, isocpp 上一堆相关的新闻,其中有一个页面罗列了该会议的全部主题, 匆匆一瞥几乎眼花缭乱,为期一个星期的会议竟有上百个演 ...