在实际的企业应用中,有时需要交叉输入,既可以横向输入,又可以纵向输入。大尺寸显示器的使用满足了这一要求,如24英吋、27英吋及以上尺寸显示器的使用。这在从纸上书写时代向信息化时代过渡阶段,还是十分有用的。主要是符合从前的工作习惯。
一、交叉输入
如图,这里是一个计件工作统计的示例。
二、主要需求
1、交叉输入。回车键后光标可以横向或纵向移动,可以切换。
2、通用功能。即列是根据需要临时生成的,不是后台数据表的列。如不同生产部门或生产线的工序。
3、自动生成行。如果行是一个一个新增的,那就没有意义了。就是要像一电子表格一样,表格已经都有了,就填写一些数就行了。有些人用电子表格很习惯。行数据一般根据主数据(单据头)生成。本例载入数据时选择不同的生产部门。
4、纵横都要求和。以便核对正确性。
5、一次性提交新增、修改、删除的数据。
三、数据表
-- 单据头 gzjjo字段列表: oid varchar 30 单据号 textread ny bpchar 6 年月 textread rq date 0 日期 dateedit yyyy-MM-dd bmdh varchar 12 部门代号 buttonedit bmmc varchar 100 部门名称 textread jjzl varchar 20 计件类别 comboedit gymc varchar 100 工艺名称 textedit scdh varchar 100 计划单号 buttonedit chxh varchar 20 产品货号 textread chdh varchar 20 存货代号 textread chmc varchar 100 存货名称 textread xh1 varchar 100 型号 textread xh2 varchar 100 规格 textread xh3 varchar 400 参数 textread gg1 varchar 100 颜色 textread gg2 varchar 100 材质 textread gg3 varchar 100 图号 textread jldw varchar 20 单位 textread jhsl numeric 18 计划数量 textread 0.00 bz varchar 200 备注 textedit tzr varchar 20 填制人 textedit shr varchar 20 审核人 textedit djr varchar 20 登记人 textedit -- 单据体 gzjjm字段列表: mid int4 32 序号 textread oid varchar 30 单据号 textread ny bpchar 6 年月 textread bmdh varchar 12 生产部门代号 buttonedit bmmc varchar 60 生产部门名称 textedit gymc varchar 100 工艺名称 textedit rybh varchar 12 人员编号 buttonedit ryxm varchar 20 人员姓名 textedit gxmc varchar 40 工序名称 buttonedit tjsl numeric 18 统计数量 textedit n0 sfgx bool 0 是否更新 checkedit gxdj numeric 18 工序单价 textedit n2 gxje numeric 18 金额 textedit n2 sfsh bool 0 是否审核 checkedit sfdj bool 0 是否登记 checkedit
上述两个表,用来存储所有计件工作量统计数据。不论何生产部门及人员。
四、关键代码
1、功能参数。
为增强通用性。功能的单据头字段、单据体字段及载入条件项目等,均可用户化定义。把它写在后台数据库函数中,窗口加载时调入该数据。有些字段是固定的,必须包含。
CREATE OR REPLACE FUNCTION public.x9_jjgzlsj( sstjmc character varying, ssyhjs character varying, sssfdj boolean) RETURNS character varying LANGUAGE 'plpgsql' COST 100 VOLATILE PARALLEL UNSAFE AS $BODY$ -- description: 计件工作量统计表 功能设计选项 DECLARE ssmsg text;ssdet text;sstname text;sshint text;ssctt text; --错误处理 BEGIN -- 参数:条件名称、用户角色、是否登记 。 -- 更改载入条件时,请在x9_zrtjcs过程中手动初始。 -- 可用的部分系统变量:{pywqj},{pdqyh},{pyhjs},{pbjmc},{ppcxh},{pyhxh},{pztmc},{psydw} -- 结果中的单引号用 ` 表示。如例 IF $1 = 'ft1oidqz' THEN RETURN 'gzjj{ppcxh}_{业务期间}_' AS xxjg; -- 结合ft1where、ft2where设置 END IF; IF $1 = 'ft1list' THEN RETURN 'oid,ny,bmdh,bmmc,gymc,jjzl,scdh,chxh,chdh,chmc,xh1,xh2,xh3,gg1,jldw,jhsl,rq,bz,tzr,shr,djr' AS xxjg; -- oid,ny,bmdh,bmmc,gymc,jjzl,rq,tzr,shr,djr 必须包括 END IF; IF $1 = 'ft1where' THEN -- 条件 生产部门代号 和 业务期间 不能省略,可能区分是否登记 IF $3 = false THEN RETURN 'oid like `gzjj{ppcxh}%` and bmdh=`{生产部门代号}` and ny=`{业务期间}` and gymc=`{工艺名称}` and djr=``' AS xxjg; ELSE RETURN 'oid like `gzjj%` and bmdh=`{生产部门代号}` and ny=`{业务期间}` and gymc=`{工艺名称}` and djr<>``' AS xxjg; END IF; END IF; IF $1 = 'ft2list' THEN RETURN 'mid,oid,ny,bmdh,bmmc,gymc,rybh,ryxm,gxmc,tjsl,sfgx,sfsh,sfdj' AS xxjg; END IF; IF $1 = 'ft2where' THEN -- 条件 生产部门代号 和 业务期间 不能省略 IF $3 = false THEN RETURN 'oid like `gzjj{ppcxh}%` and bmdh=`{生产部门代号}` and ny=`{业务期间}` and gymc=`{工艺名称}` and sfdj=false' AS xxjg; ELSE RETURN 'oid like `gzjj%` and bmdh=`{生产部门代号}` and ny=`{业务期间}` and gymc=`{工艺名称}` and sfdj<>false' AS xxjg; END IF; END IF; RETURN ''; EXCEPTION WHEN others THEN GET stacked DIAGNOSTICS ssmsg = MESSAGE_TEXT,ssdet = pg_exception_detail, sstname = TABLE_NAME, sshint = pg_exception_hint, ssctt = pg_exception_context; CALL x9_jlproc(ssmsg, ssdet, sstname, sshint, ssctt); RETURN ssmsg; END; $BODY$; ALTER FUNCTION public.x9_jjgzlsj(character varying, character varying, boolean) OWNER TO postgres;
2、初始单据体表单前端代码
VB.NET+DEVEXPRESS+NPGSQL。
Private Sub Loaddjgv() '初始单据体表gv Try If IsNothing(GridDM) Then loaderr = True Exit Sub End If GridDM.ViewCollection.Clear() mtgv = New GridView(GridDM) mtgv.BeginUpdate() mtgv.Name = "mtgv" mtgv.OptionsBehavior.AutoPopulateColumns = False GridDM.DataSource = dqdt2 GridDM.ForceInitialize() GridDM.MainView = mtgv mtgv.PopulateColumns(dqdt2) Setgv(mtgv, False) mtgv.ColumnPanelRowHeight = PanelRowHeightJj mtgv.OptionsFind.AllowFindPanel = False mtgv.OptionsBehavior.AutoUpdateTotalSummary = False '添加控件 首列 rybh AddHandler mtgv.PopupMenuShowing, AddressOf Mtgv_popupmenushowing With mtgv Dim rcb As New RepositoryItemButtonEdit With {.TextEditStyle = TextEditStyles.Standard, .MaxLength = 10} GridDM.RepositoryItems.Add(rcb) AddHandler rcb.KeyDown, AddressOf Djbuttonedit_keydown AddHandler rcb.ButtonClick, AddressOf Djbuttonedit_buttonclick '人员编号列属性 .Columns("rybh").Caption = "人员编号" .Columns("rybh").ColumnEdit = rcb .Columns("rybh").ToolTip = "" .Columns("rybh").AppearanceHeader.Options.UseTextOptions = True .Columns("rybh").AppearanceCell.TextOptions.HAlignment = HorzAlignment.Near .Columns("rybh").AppearanceCell.TextOptions.VAlignment = VertAlignment.Center .Columns("rybh").AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center .Columns("rybh").AppearanceHeader.TextOptions.VAlignment = VertAlignment.Center .Columns("rybh").AppearanceHeader.TextOptions.WordWrap = WordWrap.Wrap .Columns("rybh").OptionsColumn.AllowSort = DevExpress.Utils.DefaultBoolean.False .Columns("rybh").OptionsColumn.AllowMove = False .Columns("rybh").OptionsColumn.AllowShowHide = False .Columns("rybh").OptionsFilter.AllowFilter = False .Columns("rybh").OptionsColumn.ReadOnly = False .Columns("rybh").Fixed = FixedStyle.Left 'button 事件程序 Dim rct As New RepositoryItemTextEdit rct.ReadOnly = True GridDM.RepositoryItems.Add(rct) '人员姓名列属性 .Columns("ryxm").Caption = "人员姓名" .Columns("ryxm").ColumnEdit = rct .Columns("ryxm").ToolTip = "" .Columns("ryxm").AppearanceHeader.Options.UseTextOptions = True .Columns("ryxm").AppearanceCell.TextOptions.HAlignment = HorzAlignment.Center .Columns("ryxm").AppearanceCell.TextOptions.VAlignment = VertAlignment.Center .Columns("ryxm").AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center .Columns("ryxm").AppearanceHeader.TextOptions.VAlignment = VertAlignment.Center .Columns("ryxm").AppearanceHeader.TextOptions.WordWrap = WordWrap.Wrap .Columns("ryxm").OptionsColumn.AllowSort = DevExpress.Utils.DefaultBoolean.False .Columns("ryxm").OptionsColumn.AllowMove = False .Columns("ryxm").OptionsColumn.AllowShowHide = False .Columns("ryxm").OptionsFilter.AllowFilter = True .Columns("ryxm").OptionsColumn.ReadOnly = True .Columns("ryxm").Fixed = FixedStyle.Left Dim sitotal As New GridColumnSummaryItem() sitotal.SummaryType = SummaryItemType.Count sitotal.DisplayFormat = "共 {0} 行 " .Columns("ryxm").Summary.Add(sitotal) '数据输入列属性 For r As Integer = 0 To dtbmgx.Rows.Count - 1 Dim rc As New RepositoryItemTextEdit With {.MaxLength = 12} rc.DisplayFormat.FormatType = FormatType.Numeric rc.DisplayFormat.FormatString = "#" rc.EditFormat.FormatType = FormatType.Numeric rc.EditFormat.FormatString = "#" AddHandler rc.KeyDown, AddressOf Djview_keydown GridDM.RepositoryItems.Add(rc) Dim fd As String = dtbmgx.Rows(r).Item("gxmc").ToString.Trim .Columns(fd).Caption = fd .Columns(fd).ColumnEdit = rc .Columns(fd).ToolTip = "" .Columns(fd).AppearanceHeader.Options.UseTextOptions = True .Columns(fd).AppearanceCell.TextOptions.HAlignment = HorzAlignment.Center .Columns(fd).AppearanceCell.TextOptions.VAlignment = VertAlignment.Center .Columns(fd).AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center .Columns(fd).AppearanceHeader.TextOptions.VAlignment = VertAlignment.Center .Columns(fd).AppearanceHeader.TextOptions.WordWrap = WordWrap.Wrap .Columns(fd).OptionsColumn.AllowSort = DevExpress.Utils.DefaultBoolean.False .Columns(fd).OptionsFilter.AllowFilter = False .Columns(fd).OptionsColumn.ReadOnly = False .Columns(fd).SummaryItem.DisplayFormat = " {0:#} " .Columns(fd).SummaryItem.FieldName = fd .Columns(fd).SummaryItem.SummaryType = SummaryItemType.Sum Next .OptionsView.ShowFooter = True .OptionsMenu.ShowFooterItem = True '.appearance.evenrow.backcolor = color.fromargb(150, 237, 243, 254) '.appearance.oddrow.backcolor = color.fromargb(150, 199, 237, 204) .OptionsView.EnableAppearanceEvenRow = True .OptionsView.EnableAppearanceOddRow = True End With AddHandler mtgv.KeyUp, AddressOf Djview_keyup AddHandler mtgv.FocusedRowChanged, AddressOf Dj_focusedrowchanged AddHandler mtgv.CellValueChanged, AddressOf Dj_cellvaluechanged Dim strfd As String = "" Dim strcp As String = "" Dim strhj As String = "" '定义行合计公式 For c As Integer = 0 To mtgv.Columns.Count - 1 If mtgv.Columns(c).Visible And (InStr(mtgv.Columns(c).Caption, "*") > 0) Then strfd += mtgv.Columns(c).FieldName & "," strcp += Replace(mtgv.Columns(c).Caption, "*", "") & "," End If Dim tyname As String = mtgv.Columns(c).ColumnType.Name.ToLower Select Case tyname Case "int16", "int32", "int64", "byte", "sbyte", "uint16", "uint32", "uint64", "decimal", "double", "single" strhj += "[" & mtgv.Columns(c).FieldName & "]+" Case Else Exit Select End Select Next '增加列合计 If Len(strhj) > 2 Then strhj = Mid(strhj, 1, Len(strhj) - 1) End If Dim unbcolumn As GridColumn = mtgv.Columns.AddField("total") unbcolumn.Caption = "合计" unbcolumn.AppearanceHeader.Options.UseTextOptions = True unbcolumn.AppearanceCell.TextOptions.HAlignment = HorzAlignment.Center unbcolumn.AppearanceCell.TextOptions.VAlignment = VertAlignment.Center unbcolumn.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center unbcolumn.AppearanceHeader.TextOptions.VAlignment = VertAlignment.Center unbcolumn.AppearanceHeader.TextOptions.WordWrap = WordWrap.Wrap unbcolumn.VisibleIndex = mtgv.Columns.Count unbcolumn.UnboundType = DevExpress.Data.UnboundColumnType.Decimal unbcolumn.UnboundExpression = strhj unbcolumn.OptionsColumn.AllowEdit = False unbcolumn.DisplayFormat.FormatType = DevExpress.Utils.FormatType.Numeric unbcolumn.DisplayFormat.FormatString = " {0:#} " mtgv.EndUpdate() GridDM.Tag = "gvend" GridDM.UseEmbeddedNavigator = False GridDM.Visible = True Catch ex As Exception loaderr = True ExShow("初始单据体视图", ex.Message, ex.Source, ex.StackTrace) End Try End Sub
3、加载单据数据
VB.NET+DEVEXPRESS+NPGSQL。
Private Sub Djload() Try sfzj = 0 dqdjs = dt1.Rows.Count loadfm = True If dqdjh < 0 Then Fmxmrw(True) dt2.DefaultView.RowFilter = "false" Lczs.Text = "0/0" Lctz.Text = "填制:" Lcdj.Text = "审核:" Lcsh.Text = "登记:" Else Gvclear(mtgv) Baroid.EditValue = dt1.Rows(dqdjh).Item(ft1oid).ToString Fmxmload() dt2.DefaultView.RowFilter = ft2oid & "='" & Baroid.EditValue.ToString & "'" dt2.DefaultView.RowStateFilter = (DataViewRowState.CurrentRows) sfsp = dt1.Rows(dqdjh).Item(ft1sh).ToString <> "" sfdj = dt1.Rows(dqdjh).Item(ft1dj).ToString <> "" Lctz.Text = "填制:" & dt1.Rows(dqdjh).Item(ft1tz).ToString Lcsh.Text = "审核:" & dt1.Rows(dqdjh).Item(ft1sh).ToString Lcdj.Text = "登记:" & dt1.Rows(dqdjh).Item(ft1dj).ToString If dt2.DefaultView.Count > 0 Then Dim gxstr As String = "" Dim gxlost As String = "" For c As Integer = 0 To dtbmgx.Rows.Count - 1 gxstr = gxstr & "`" & dtbmgx.Rows(c).Item("gxmc") & "`" Next With dqdt2 .Rows.Clear() .AcceptChanges() Dim nrow() As DataRow Dim nrow2 As DataRow Dim rybh As String = "" Dim ryxm As String = "" Dim gxmc As String Dim tjsl As Double = 0 Dim dqh As Integer = -1 For r As Integer = 0 To dt2.DefaultView.Count - 1 If rybh <> dt2.DefaultView(r).Item("rybh") Then nrow = .Select("rybh='" & dt2.DefaultView(r).Item("rybh") & "'") If nrow.Length > 0 Then dqh = .Rows.IndexOf(nrow(0)) Else nrow2 = .NewRow nrow2.Item("rybh") = dt2.DefaultView(r).Item("rybh") nrow2.Item("ryxm") = dt2.DefaultView(r).Item("ryxm") .Rows.Add(nrow2) nrow = .Select("rybh='" & dt2.DefaultView(r).Item("rybh") & "'") If nrow.Length > 0 Then dqh = .Rows.IndexOf(nrow(0)) End If End If End If rybh = dt2.DefaultView(r).Item("rybh") gxmc = dt2.DefaultView(r).Item("gxmc") If InStr(gxstr, "`" & gxmc & "`") > 0 Then If dqh >= 0 Then tjsl = dt2.DefaultView(r).Item("tjsl") If tjsl <> 0 Then .Rows(dqh).Item(gxmc) = dt2.DefaultView(r).Item("tjsl") End If End If Else If gxlost = "" Then gxlost = gxmc Else If InStr(gxlost, gxmc) <= 0 Then gxlost = gxlost & "," & gxmc End If End If End If Next .AcceptChanges() If gxlost.Length > 0 Then XxShow("工序名称:" & gxlost & " 在当前工作中心不存在!" & vbCrLf & "这些数据在数据库中依然存在,这将导致严重的数据错误,请删除后重新输入!" & vbCrLf & "文件导入数据时,需要区分工作中心。", Me) End If nrow = Nothing nrow2 = Nothing End With Else Dqdt2cs() dqdt2.AcceptChanges() End If End If mtgv.RefreshData() mtgv.OptionsBehavior.ReadOnly = True If dt1.Rows.Count > 0 Then If mtgv.RowCount <= 0 Then Lczs.Text = "[" & (dqdjh + 1).ToString.Trim & "/" & dt1.Rows.Count.ToString.Trim & "张][0/0行]" Else Lczs.Text = "[" & (dqdjh + 1).ToString.Trim & "/" & dt1.Rows.Count.ToString.Trim & "张][" & (mtgv.FocusedRowHandle + 1).ToString.Trim & "/" & mtgv.RowCount.ToString.Trim & "行]" End If End If dqoid = Baroid.EditValue.ToString Barenabled() loadfm = False Catch ex As Exception ExShow("加载单据[" & dqoid & "]", ex.Message, ex.Source, ex.StackTrace, Me) End Try End Sub Private Sub Dqdt2cs() '初始计件工作量统计表数据 Dim nrow As DataRow With dqdt2 .Rows.Clear() .AcceptChanges() For r As Integer = 0 To dtbmry.Rows.Count - 1 nrow = .NewRow nrow.Item("rybh") = dtbmry.Rows(r).Item("rybh") nrow.Item("ryxm") = dtbmry.Rows(r).Item("ryxm") .Rows.Add(nrow) Next .AcceptChanges() End With End Sub
4、保存数据代码
VB.NET+DEVEXPRESS+NPGSQL。
Private Sub Savedjm() '保存数据到单据体记录集 Try savem = True 'mid,oid,ny,bmdh,rybh,rymc,gxmc,tjsl dqoid = Baroid.EditValue.ToString Dim midc As Integer = 0 Dim dt2c As New DataTable Dim mrow() As DataRow Dim nmrow As DataRow dt2.DefaultView.RowFilter = ft2oid & "='" & dqoid & "'" dt2.DefaultView.RowStateFilter = (DataViewRowState.CurrentRows) With dt2 For r As Integer = .DefaultView.Count - 1 To 0 Step -1 .DefaultView(r).Item("sfgx") = 0 Next End With With mtgv For r As Integer = 0 To .RowCount - 1 Dim dqh As Integer Dim gxmc As String Dim dqbh As String = .GetRowCellValue(r, .Columns("rybh")) Dim dqxm As String = .GetRowCellValue(r, .Columns("ryxm")) Dim tjsl As Double For c As Integer = 2 To .Columns.Count - 2 '最后一列为合计列 gxmc = .Columns(c).FieldName If Not IsDBNull(.GetRowCellValue(r, .Columns(gxmc))) Then tjsl = .GetRowCellValue(r, .Columns(gxmc)) Else tjsl = 0 End If If tjsl = 0 And c <> 2 Then Continue For End If mrow = dt2.Select("oid='" & dqoid & "' and rybh='" & dqbh & "' and gxmc='" & gxmc & "'") If mrow.Length > 0 Then dqh = dt2.Rows.IndexOf(mrow(0)) dt2.Rows(dqh).Item("tjsl") = tjsl dt2.Rows(dqh).Item("sfgx") = 1 Else nmrow = dt2.NewRow nmrow.Item("mid") = hyDB.DBInteger("select x9_djmid('" & ft2 & "','" & ft2mid & "')") nmrow.Item("oid") = dqoid nmrow.Item("ny") = dqywqj nmrow.Item("bmdh") = dqbmdh nmrow.Item("bmmc") = dqbmmc nmrow.Item("gymc") = dqgymc nmrow.Item(ft2shbjzd) = 0 nmrow.Item(ft2djbjzd) = 0 nmrow.Item("rybh") = dqbh nmrow.Item("ryxm") = dqxm nmrow.Item("gxmc") = gxmc nmrow.Item("tjsl") = tjsl nmrow.Item("sfgx") = 1 dt2.Rows.Add(nmrow) End If Next Next End With With dt2 For r As Integer = .DefaultView.Count - 1 To 0 Step -1 If .DefaultView(r).Item("sfgx") = 0 Then .DefaultView(r).Delete() End If Next End With savem = False hyDB.DBclose() Catch ex As Exception ExShow("保存单据体数据", ex.Message, ex.Source, ex.StackTrace, Me) savem = False End Try End Sub
之后用户可以使用窗口按钮提交数据库,或在退出时自动提交。
五、总结
这样,载入时,选择不同的参数,就可以输入不同生产部门的计件工作量数据了。
这一特定输入形式,在实际应用中受到很多用户的欢迎,甚至有些操作者认为这是必需的。
在本人以往二十多年的开发的不同产品中,均使用了这一形式,虽然使用的语言、控件不同,但性是一样的。
有同样需要的,可以参考或探讨。