1104 lines
41 KiB
VB.net
1104 lines
41 KiB
VB.net
Imports System.ComponentModel
|
||
Imports System.Drawing
|
||
Imports System.Drawing.Drawing2D
|
||
Imports System.Text
|
||
Imports System.Threading
|
||
Imports System.Windows.Forms
|
||
Imports UTS_Core.DebugLog
|
||
Imports UTS_Core.UTSModule.DbConnect
|
||
Imports UTS_Core.UTSModule.DbTableModel.Customer
|
||
Imports UTS_Core.UTSModule.Production
|
||
Imports UTS_Core.UTSModule.Station
|
||
Imports UTS_Core.UTSModule.Station.StationTestPlan
|
||
Imports UTS_Core.UTSModule.Test.Command.SystemCommand
|
||
Imports UTS_Core.UTSModule.Test.Controls
|
||
Imports UTS_Core.UTSModule.Test.StatusMonitor
|
||
Imports UTS_Core.UTSModule.Test.StatusMonitor.TestStatusMonitor
|
||
|
||
|
||
Namespace UTSModule.Test
|
||
Public Class FrmStationTest
|
||
Implements IUtsTest
|
||
Implements IProcessStation
|
||
Implements IProductionLine
|
||
|
||
Private _utsApp As UtsAppForm
|
||
|
||
|
||
''' <summary> 测试错误代码管理器</summary>
|
||
Private _errCodeManager As ErrCodeManager
|
||
|
||
''' <summary>测试线程</summary>
|
||
Private _testThread As Thread
|
||
|
||
''' <summary>测试站信息</summary>
|
||
Public TestProcessStation As ProcessStation
|
||
|
||
''' <summary>测试记录表格</summary>
|
||
Private _recordGrid As TestRecordGrid
|
||
|
||
#Region "UTS窗体公共模块"
|
||
Public Sub ShowForm(parentControl As Control)
|
||
FormBorderStyle = FormBorderStyle.None
|
||
TopLevel = False
|
||
Dock = DockStyle.Fill
|
||
Parent = parentControl
|
||
|
||
Show()
|
||
End Sub
|
||
|
||
''' <summary>
|
||
''' 产线变化
|
||
''' </summary>
|
||
Public Sub ProductionLineChanged() Implements IProductionLine.ProductionLineChanged
|
||
'Todo:产线变化代码
|
||
ApplicationLog.WriteInfoLog($"测试页面生产线变更中。")
|
||
|
||
|
||
ApplicationLog.WriteInfoLog($"测试页面生产线变更完成。")
|
||
End Sub
|
||
|
||
''' <summary>
|
||
''' 站位变化
|
||
''' </summary>
|
||
|
||
Public Sub Station_Changed() Implements IProcessStation.StationChanged
|
||
ApplicationLog.WriteInfoLog($"测试页面站位变更中,PN:{_utsApp.ProcessStation.ParentProject.Name} - SN:{_utsApp.ProcessStation.Name} - TP:{_utsApp.ProcessStation.Packet.Name}!")
|
||
|
||
TestProcessStation = _utsApp.ProcessStation
|
||
|
||
_tester.ProcessStation = TestProcessStation '绑定测试器的流程
|
||
|
||
_recordGrid.StationPlan = CType(TestProcessStation.Packet.StationPlan, StationTestPlan)
|
||
|
||
LblStation.Text = $"{TestProcessStation.ParentProject.Name} : {TestProcessStation.Name}"
|
||
|
||
PicStepTip.Image = TestProcessStation.Packet.StationImage '重置提示图
|
||
|
||
|
||
'初始化提示信息图执行类中耦合变量
|
||
ShowTipImageExecutor.TipImageControl = PicStepTip
|
||
ShowTipsExecutor.TipControl = LblTipString
|
||
|
||
DbConnector.UtsCreateTestLogTableToLocal(TestProcessStation.ParentProject.Index, TestProcessStation.StationID) '创建本地记录表
|
||
|
||
InitChartData(TestProcessStation.ParentProject.Index, TestProcessStation.StationID) '更新本地图表数据
|
||
UpdateTestLogToCsv(_tester.GetFixedModule(FixedModuleEnum.Main).RowList.ToArray()) '更新CSV文件
|
||
|
||
ApplicationLog.WriteInfoLog($"测试页面站位变更完成!")
|
||
End Sub
|
||
#End Region
|
||
|
||
#Region "Form Event"
|
||
|
||
Dim gRunFlag As Int16 = 0
|
||
Private Sub FrmStationTest_Load(sender As Object, e As EventArgs) Handles Me.Load
|
||
ApplicationLog.WriteInfoLog($"测试页面加载中。")
|
||
|
||
'初始化UTS窗体信息,失败则关闭窗体
|
||
If InitializeUtsApp() = False Then Return
|
||
gRunFlag = 1
|
||
|
||
'初始化错误代码
|
||
_errCodeManager = ErrCodeManager.CreateManager()
|
||
gRunFlag = 2
|
||
|
||
'初始化窗体页面
|
||
InitializeForm()
|
||
gRunFlag = 3
|
||
|
||
'初始化测试器
|
||
InitTester()
|
||
gRunFlag = 4
|
||
|
||
AddHandler UtsKeyValueMonitor.UtsKeyDown, AddressOf UtsKeyDownCallback '按键检测
|
||
AddHandler StationEditStatusMonitor.StationEditStatusChanged, AddressOf StationEditStatusChanged '流程编辑检测
|
||
|
||
ApplicationLog.WriteInfoLog($"测试页面加载完成。")
|
||
gRunFlag = 5
|
||
|
||
End Sub
|
||
|
||
|
||
Private Function InitializeUtsApp() As Boolean
|
||
_utsApp = UtsAppForm.CreateSingleton()
|
||
_utsApp.AddStatisticsObserver(Me)
|
||
|
||
Try
|
||
If _utsApp.IsInitialized = False Then
|
||
_utsApp.Initialize() 'Todo:可根据需要限定可选站位
|
||
End If
|
||
Catch ex As Exception
|
||
ApplicationLog.WriteErrorLog($"初始化窗体失败,原因:{ex.Message}!")
|
||
|
||
MsgBox($"初始化窗体失败,原因:{ex.Message}")
|
||
Close()
|
||
Return False
|
||
End Try
|
||
|
||
Return True
|
||
End Function
|
||
|
||
Private Sub InitializeForm()
|
||
InitBarChart()
|
||
|
||
InitPieChart()
|
||
|
||
InitRecordGrid()
|
||
End Sub
|
||
|
||
|
||
Private Sub Btn_StartTest_Click(sender As Object, e As EventArgs) Handles BtnStartTest.Click
|
||
Static waitStop As Boolean = False
|
||
If waitStop = True Then Return
|
||
waitStop = True
|
||
StartTestEvent()
|
||
waitStop = False
|
||
End Sub
|
||
|
||
|
||
Private Sub StationEditStatusChanged(sender As Object, e As StationEditStatusChangedEventArgs)
|
||
If e.Status <> StationEditStatusMonitor.StationEditStatusEnum.Saved Then Return
|
||
|
||
If GrdStepTestRecord.InvokeRequired Then '判断是否需要开委托
|
||
GrdStepTestRecord.Invoke(New Action(Of Object, StationEditStatusChangedEventArgs)(AddressOf StationEditStatusChanged), New Object() {sender, e})
|
||
Return
|
||
End If
|
||
|
||
_recordGrid.UpdateStepTestRecord()
|
||
End Sub
|
||
#End Region
|
||
|
||
#Region "外部按键事件"
|
||
Private Sub UtsKeyDownCallback(sender As Object, e As UtsKeyDownEventArgs)
|
||
If BtnStartTest.InvokeRequired Then
|
||
BtnStartTest.Invoke(New Action(Of UtsKeyValueMonitor.UtsKeyValueEnum)(AddressOf UpdateKey), New Object() {e.KeyValue})
|
||
Else
|
||
UpdateKey(e.KeyValue)
|
||
End If
|
||
End Sub
|
||
|
||
Private Sub UpdateKey(key As UtsKeyValueMonitor.UtsKeyValueEnum)
|
||
Static waitStop As Boolean = False
|
||
If key = UtsKeyValueMonitor.UtsKeyValueEnum.Start Then
|
||
If waitStop = True Then Return
|
||
waitStop = True
|
||
StartTestEvent()
|
||
waitStop = False
|
||
End If
|
||
End Sub
|
||
#End Region
|
||
|
||
#Region "CSV测试记录"
|
||
Private Sub UpdateTestLogToCsv(nodes() As RowNode)
|
||
Dim dirPath As String = $"{Application.StartupPath}\LocalTestLog"
|
||
Dim filePath As String = $"{dirPath}\TestLog_{Now:yyyyMMdd}.csv"
|
||
|
||
If IO.Directory.Exists(dirPath) = False Then IO.Directory.CreateDirectory(dirPath)
|
||
|
||
Dim str As New StringBuilder
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Start{vbCrLf}")
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Load,{TestProcessStation.Packet.FileName}{vbCrLf}")
|
||
|
||
Dim testItems As New StringBuilder
|
||
Dim testSteps As New StringBuilder
|
||
Dim testCmdTypes As New StringBuilder
|
||
Dim testCmdNames As New StringBuilder
|
||
|
||
Dim param1 As New StringBuilder
|
||
Dim param2 As New StringBuilder
|
||
Dim param3 As New StringBuilder
|
||
Dim param4 As New StringBuilder
|
||
Dim param5 As New StringBuilder
|
||
Dim param6 As New StringBuilder
|
||
Dim param7 As New StringBuilder
|
||
Dim param8 As New StringBuilder
|
||
|
||
For Each node As RowNode In nodes
|
||
If String.IsNullOrWhiteSpace(node.RecordName) Then
|
||
Continue For
|
||
End If
|
||
|
||
testItems.Append(","c)
|
||
testItems.Append(node.RecordName)
|
||
|
||
testSteps.Append(","c)
|
||
testSteps.Append(node.RowListIndex)
|
||
|
||
testCmdTypes.Append(","c)
|
||
testCmdTypes.Append(node.CommandType)
|
||
|
||
testCmdNames.Append(","c)
|
||
testCmdNames.Append(node.Command)
|
||
|
||
param1.Append(","c)
|
||
If node.Parameters.Count > 0 Then param1.Append(node.Parameters(0).Value)
|
||
|
||
param2.Append(","c)
|
||
If node.Parameters.Count > 1 Then param2.Append(node.Parameters(1).Value)
|
||
|
||
param3.Append(","c)
|
||
If node.Parameters.Count > 2 Then param3.Append(node.Parameters(2).Value)
|
||
|
||
param4.Append(","c)
|
||
If node.Parameters.Count > 3 Then param4.Append(node.Parameters(3).Value)
|
||
|
||
param5.Append(","c)
|
||
If node.Parameters.Count > 4 Then param5.Append(node.Parameters(4).Value)
|
||
|
||
param6.Append(","c)
|
||
If node.Parameters.Count > 5 Then param6.Append(node.Parameters(5).Value)
|
||
|
||
param7.Append(","c)
|
||
If node.Parameters.Count > 6 Then param7.Append(node.Parameters(6).Value)
|
||
|
||
param8.Append(","c)
|
||
If node.Parameters.Count > 7 Then param8.Append(node.Parameters(7).Value)
|
||
Next
|
||
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},TestStep,{testSteps}{vbCrLf}")
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},TestItem,{testItems}{vbCrLf}")
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},CmdType,{testCmdTypes}{vbCrLf}")
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Command,{testCmdNames}{vbCrLf}")
|
||
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_1,{param1}{vbCrLf}")
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_2,{param2}{vbCrLf}")
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_3,{param3}{vbCrLf}")
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_4,{param4}{vbCrLf}")
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_5,{param5}{vbCrLf}")
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_6,{param6}{vbCrLf}")
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_7,{param7}{vbCrLf}")
|
||
str.Append($",{Now:yyyyMMdd},{Now:HH:mm:ss},Parameter_8,{param8}{vbCrLf}")
|
||
|
||
Try
|
||
IO.File.AppendAllText(filePath, str.ToString())
|
||
Catch ex As Exception
|
||
ApplicationLog.WriteErrorLog($"更新CSV文件失败,原因:{ex.Message}")
|
||
UtsMsgBox.ShowDialog($"更新CSV文件失败,原因:{ex.Message}")
|
||
End Try
|
||
End Sub
|
||
|
||
|
||
''' <summary>
|
||
''' 存储单笔测试记录至CSV文件
|
||
''' </summary>
|
||
Private Sub SaveTestLogToCsv(result As TestResult)
|
||
Dim dirPath As String = $"{Application.StartupPath}\LocalTestLog"
|
||
Dim filePath As String = $"{dirPath}\TestLog_{Now:yyyyMMdd}.csv"
|
||
|
||
'设置写入内容
|
||
Dim str As New StringBuilder
|
||
str.Append($"{result.DUT_SN},{Now:yyyyMMdd},{Now:HH:mm:ss},{result.TestResult}")
|
||
If result.FailSteps.Count > 0 Then
|
||
str.Append($",{result.FailSteps(0).RowListIndex}")
|
||
Else
|
||
str.Append($",")
|
||
End If
|
||
str.Append($",{result.DUT_SN}")
|
||
For Each keyValuePair As KeyValuePair(Of String, String) In result.CustomRecord
|
||
str.Append($",{keyValuePair.Value}")
|
||
Next
|
||
str.Append(vbCrLf)
|
||
|
||
Try
|
||
IO.File.AppendAllText(filePath, str.ToString())
|
||
Catch ex As Exception
|
||
ApplicationLog.WriteErrorLog($"保存测试结果至CSV文件失败:{ex.Message}")
|
||
UtsMsgBox.ShowDialog($"保存测试结果至CSV文件失败:{ex.Message}")
|
||
End Try
|
||
End Sub
|
||
#End Region
|
||
|
||
#Region "统一查询图表数据"
|
||
Private ReadOnly _pieResults As New List(Of PieChartResult)
|
||
|
||
Private ReadOnly _barResults As New List(Of BarChartResult)
|
||
|
||
Private ReadOnly _pointResults As New List(Of PointChartResult)
|
||
|
||
Private Sub InitChartData(pid As Integer, sid As Integer)
|
||
ApplicationLog.WriteInfoLog($"测试页面统计图表绘制中。")
|
||
|
||
_pieResults.Clear()
|
||
_barResults.Clear()
|
||
_pointResults.Clear()
|
||
|
||
Dim dtTable As DataTable = DbConnector.GetTodayTestResult(pid, sid)
|
||
|
||
Dim result As New TestResult
|
||
For Each row As DataRow In dtTable.Rows
|
||
Dim a As String = row($"{TestLogTable.ColNames.StartTime}").ToString()
|
||
|
||
If Date.TryParse(a, result.StartTime) = False Then Continue For
|
||
|
||
Dim c As String = row($"{TestLogTable.ColNames.TestResult}").ToString()
|
||
If String.Compare(c, "1") = 0 Then
|
||
result.TestResult = TestResult.TestResultEnum.Pass
|
||
Else
|
||
result.TestResult = TestResult.TestResultEnum.Fail
|
||
End If
|
||
|
||
result.DUT_SN = row($"{TestLogTable.ColNames.DUT_SN}").ToString()
|
||
If String.IsNullOrWhiteSpace(result.DUT_SN) Then Continue For
|
||
|
||
result.ErrCode = row($"{TestLogTable.ColNames.ErrCode}").ToString()
|
||
|
||
AddPieChart(result)
|
||
|
||
AddBarChart(result)
|
||
|
||
AddPointChart(result)
|
||
Next
|
||
|
||
RedrawPointChart()
|
||
|
||
ApplicationLog.WriteInfoLog($"测试页面统计图表绘制完成。")
|
||
End Sub
|
||
#End Region
|
||
|
||
#Region "良率统计"
|
||
Private Sub InitPieChart()
|
||
ChartPie.Header.Text = "良率统计" '标题
|
||
ChartPie.Header.Visible = False '隐藏标题
|
||
|
||
ChartPie.Legend.Alignment = Steema.TeeChart.LegendAlignments.Right
|
||
ChartPie.Legend.Font.Brush.Color = Color.Gray
|
||
ChartPie.Legend.Font.SizeFloat = 8.0!
|
||
ChartPie.Legend.Transparent = True
|
||
|
||
ChartPie.Walls.Back.Visible = False
|
||
ChartPie.Walls.Back.Transparent = True
|
||
|
||
' TcPie.ExplodeBiggest = 10 '最大饼块与饼图分割位置
|
||
TcPie.ExplodedSlice.Add(10)
|
||
TcPie.Circled = True '饼图圆形
|
||
TcPie.Transparency = 10
|
||
TcPie.UniqueCustomRadius = True
|
||
TcPie.UseExtendedNumRange = False
|
||
|
||
TcPie.Frame.Circled = True
|
||
|
||
TcPie.Pen.Visible = False '取消绘制边框
|
||
|
||
TcPie.Marks.Font.Brush.Color = Color.White '标签内容字体颜色
|
||
TcPie.Marks.Font.Name = $"Consolas" '标签内容字体名
|
||
TcPie.Marks.Shadow.Visible = False
|
||
TcPie.Marks.Transparent = True
|
||
TcPie.Marks.Visible = True
|
||
TcPie.Marks.Style = Steema.TeeChart.Styles.MarksStyles.Percent '百分比
|
||
TcPie.MarksPie.InsideSlice = True
|
||
|
||
TcPie.YValues.Order = Steema.TeeChart.Styles.ValueListOrder.Descending '倒序排序
|
||
End Sub
|
||
|
||
|
||
Private Sub AddPieChart(result As TestResult)
|
||
Dim code As String
|
||
Dim msg As String
|
||
Dim color As Color
|
||
|
||
If result.TestResult = TestResult.TestResultEnum.Pass Then
|
||
code = "PASS"
|
||
msg = "测试通过"
|
||
color = _errCodeManager("9002").Color
|
||
Else
|
||
If _errCodeManager.IndexOf(result.ErrCode) <> -1 Then
|
||
code = result.ErrCode
|
||
msg = _errCodeManager(result.ErrCode).Msg
|
||
color = _errCodeManager(result.ErrCode).Color
|
||
Else
|
||
code = "9001"
|
||
msg = _errCodeManager(code).Msg
|
||
color = _errCodeManager(code).Color
|
||
End If
|
||
End If
|
||
|
||
|
||
Dim addPie As Boolean = True
|
||
For i As Integer = 0 To _pieResults.Count - 1
|
||
If _pieResults(i).CodeEqual(code) Then
|
||
_pieResults(i).AddResult()
|
||
addPie = False
|
||
Exit For
|
||
End If
|
||
Next
|
||
|
||
If addPie Then
|
||
Dim pieResult As New PieChartResult(code, msg, color)
|
||
pieResult.AddResult()
|
||
_pieResults.Add(pieResult)
|
||
End If
|
||
|
||
ReDrawPie()
|
||
End Sub
|
||
|
||
Private Sub ReDrawPie()
|
||
TcPie.BeginUpdate()
|
||
TcPie.Clear()
|
||
|
||
For i As Integer = 0 To _pieResults.Count - 1
|
||
TcPie.Add(_pieResults(i).Count, _pieResults(i).Code & " : " & _pieResults(i).Msg, _pieResults(i).Color)
|
||
Next
|
||
|
||
TcPie.EndUpdate()
|
||
End Sub
|
||
|
||
|
||
Class PieChartResult
|
||
Sub New(code As String, msg As String, color As Color)
|
||
Me.Code = code
|
||
Me.Msg = msg
|
||
Me.Color = color
|
||
End Sub
|
||
|
||
|
||
Property Code() As String
|
||
|
||
Property Msg() As String
|
||
|
||
Property Color() As Color
|
||
|
||
Property Count() As Integer
|
||
|
||
Public Function CodeEqual(srcCode As String) As Boolean
|
||
If String.Compare(Code, srcCode) = 0 Then
|
||
Return True
|
||
End If
|
||
|
||
Return False
|
||
End Function
|
||
|
||
Public Sub AddResult()
|
||
Count += 1
|
||
End Sub
|
||
End Class
|
||
#End Region
|
||
|
||
#Region "图表生产统计"
|
||
Private Sub InitBarChart()
|
||
ChartBar.Header.Text = "生产统计" '标题
|
||
ChartBar.Header.Visible = False '隐藏标题
|
||
|
||
ChartBar.Legend.Transparent = True '刻印说明
|
||
ChartBar.Legend.Alignment = Steema.TeeChart.LegendAlignments.Top
|
||
|
||
TcBarPass.Pen.Visible = False
|
||
TcBarPass.Brush.Color = _errCodeManager("9002").Color
|
||
TcBarPass.Brush.Transparency = 40
|
||
TcBarPass.MultiBar = Steema.TeeChart.Styles.MultiBars.Stacked '与其他柱状图并列显示
|
||
TcBarPass.Marks.Transparent = True '标记提示边框透明
|
||
TcBarPass.Marks.Style = Steema.TeeChart.Styles.MarksStyles.Value '提示标签类型为数值
|
||
TcBarPass.Marks.AutoPosition = False
|
||
TcBarPass.MarksLocation = Steema.TeeChart.Styles.MarksLocation.Start '标签文本在柱状图上面显示
|
||
TcBarPass.Legend.Text = "Pass"
|
||
|
||
TcBarFail.Pen.Visible = False
|
||
TcBarFail.Brush.Color = _errCodeManager("9003").Color
|
||
TcBarFail.Brush.Transparency = 40
|
||
TcBarFail.MultiBar = Steema.TeeChart.Styles.MultiBars.Stacked '与其他柱状图并列显示
|
||
TcBarFail.Marks.Transparent = True '标记提示边框透明
|
||
TcBarFail.Marks.Style = Steema.TeeChart.Styles.MarksStyles.Value '提示标签类型为数值
|
||
TcBarFail.Marks.AutoPosition = False
|
||
|
||
TcBarFail.MarksLocation = Steema.TeeChart.Styles.MarksLocation.Start '标签文本在柱状图上面显示
|
||
TcBarFail.Legend.Text = "Fail"
|
||
End Sub
|
||
|
||
|
||
Dim gAllCount As Integer = 0
|
||
Dim gPassCount As Integer = 0
|
||
Dim gFailCount As Integer = 0
|
||
Private Sub AddBarChart(result As TestResult)
|
||
'填充内存
|
||
Dim addBar As Boolean
|
||
Dim tmp As BarChartResult
|
||
|
||
If _barResults.Count > 0 Then
|
||
If _barResults(_barResults.Count - 1).TimeEqual(result.StartTime) Then
|
||
tmp = _barResults(_barResults.Count - 1)
|
||
Else
|
||
If result.StartTime.Hour = 0 Then
|
||
_barResults.Clear() '过零点则清空
|
||
TcBarPass.Clear()
|
||
TcBarFail.Clear()
|
||
End If
|
||
|
||
tmp = New BarChartResult(result.StartTime)
|
||
_barResults.Add(tmp)
|
||
|
||
If _barResults.Count > 8 Then '超过八个小时,移除前一小时数据
|
||
_barResults.RemoveAt(0)
|
||
addBar = False
|
||
Else
|
||
addBar = True
|
||
End If
|
||
End If
|
||
Else
|
||
tmp = New BarChartResult(result.StartTime)
|
||
_barResults.Add(tmp)
|
||
addBar = True
|
||
End If
|
||
tmp.AddResult(result.TestResult = TestResult.TestResultEnum.Pass)
|
||
|
||
'填充图表
|
||
If addBar Then
|
||
TcBarPass.Add(tmp.RecordTime, tmp.PassCount)
|
||
TcBarFail.Add(tmp.RecordTime, tmp.FailCount)
|
||
Else
|
||
RedrawBarChart()
|
||
End If
|
||
|
||
'更新测试计数 Momo 2023-11-14
|
||
gAllCount += 1
|
||
If result.TestResult = TestResult.TestResultEnum.Pass Then
|
||
gPassCount += 1
|
||
Else
|
||
gFailCount += 1
|
||
End If
|
||
|
||
Try
|
||
TssLblTestCount.Text = "Count:" & gAllCount
|
||
TssLblPassCount.Text = "Pass:" & gPassCount
|
||
TssLblFailCount.Text = "Fail:" & gFailCount
|
||
Catch ex As Exception
|
||
|
||
End Try
|
||
|
||
End Sub
|
||
|
||
Private Sub RedrawBarChart()
|
||
TcBarPass.Clear()
|
||
TcBarFail.Clear()
|
||
For i As Integer = 0 To _barResults.Count - 1
|
||
TcBarPass.Add(_barResults(i).RecordTime, _barResults(i).PassCount)
|
||
TcBarFail.Add(_barResults(i).RecordTime, _barResults(i).FailCount)
|
||
Next
|
||
End Sub
|
||
|
||
Class BarChartResult
|
||
Sub New(time As Date)
|
||
RecordTime = New DateTime(time.Year, time.Month, time.Day, time.Hour, 0, 0)
|
||
PassCount = 0
|
||
FailCount = 0
|
||
AllCount = 0
|
||
End Sub
|
||
|
||
Property RecordTime() As DateTime
|
||
|
||
Property PassCount As Integer
|
||
|
||
Property FailCount As Integer
|
||
|
||
Property AllCount As Integer
|
||
|
||
|
||
|
||
Public Function TimeEqual(srcTime As DateTime) As Boolean
|
||
If RecordTime.Day = srcTime.Day AndAlso RecordTime.Hour = srcTime.Hour Then
|
||
Return True
|
||
End If
|
||
|
||
Return False
|
||
End Function
|
||
|
||
|
||
Public Sub AddResult(passed As Boolean)
|
||
If passed Then
|
||
PassCount += 1
|
||
Else
|
||
FailCount += 1
|
||
End If
|
||
|
||
AllCount += 1
|
||
|
||
|
||
End Sub
|
||
|
||
End Class
|
||
|
||
#End Region
|
||
|
||
#Region "点阵生产统计"
|
||
|
||
''' <summary>当前绘制图形宽度</summary>
|
||
Private _drawW As Integer
|
||
|
||
''' <summary>当前绘制图形坐标点X</summary>
|
||
Private _drawX As Integer
|
||
|
||
''' <summary>当前绘制图形坐标点Y</summary>
|
||
Private _drawY As Integer
|
||
|
||
''' <summary>当前绘制图形单行最大上限</summary>
|
||
Private _drawLineMaxCount As Integer
|
||
|
||
''' <summary>
|
||
''' 添加绘制测试结果
|
||
''' </summary>
|
||
''' <param name="result"></param>
|
||
Private Sub AddPointChart(result As TestResult)
|
||
Dim a As New PointChartResult With {.BarCode = result.DUT_SN}
|
||
If result.TestResult = TestResult.TestResultEnum.Pass Then
|
||
a.Result = True
|
||
a.Color = _errCodeManager("9002").Color
|
||
Else
|
||
a.Result = False
|
||
If _errCodeManager.IndexOf(result.ErrCode) <> -1 Then
|
||
a.Color = _errCodeManager(result.ErrCode).Color
|
||
Else
|
||
a.Color = _errCodeManager("9001").Color
|
||
End If
|
||
End If
|
||
_pointResults.Add(a)
|
||
|
||
DrawPointChart(_pointResults.Count - 1) '从0开始
|
||
End Sub
|
||
|
||
|
||
Private Sub DrawPointChart(index As Integer)
|
||
If PnlPoint.InvokeRequired Then
|
||
PnlPoint.Invoke(New Action(Of Integer)(AddressOf DrawPointChart), New Object() {index})
|
||
Return
|
||
End If
|
||
|
||
Using g As Graphics = PnlPoint.CreateGraphics()
|
||
g.SmoothingMode = SmoothingMode.HighQuality '抗锯齿
|
||
If index = 0 Then
|
||
ResetPointChart()
|
||
ElseIf index Mod _drawLineMaxCount = 0 Then
|
||
_drawY += _drawW + 2
|
||
_drawX = 2
|
||
Else
|
||
_drawX += _drawW + 2
|
||
End If
|
||
|
||
g.FillEllipse(New SolidBrush(_pointResults(index).Color), New Rectangle(_drawX, _drawY, _drawW, _drawW))
|
||
End Using
|
||
End Sub
|
||
|
||
Private Sub ResetPointChart()
|
||
_drawW = 6
|
||
_drawX = 2
|
||
_drawY = 2
|
||
_drawLineMaxCount = PnlPoint.Width \ (2 + _drawW)
|
||
End Sub
|
||
|
||
Private Sub RedrawPointChart()
|
||
Using g As Graphics = PnlPoint.CreateGraphics()
|
||
g.SmoothingMode = SmoothingMode.HighQuality '抗锯齿
|
||
For index As Integer = 0 To _pointResults.Count - 1
|
||
If index = 0 Then
|
||
ResetPointChart()
|
||
ElseIf index Mod _drawLineMaxCount = 0 Then
|
||
_drawY += _drawW + 2
|
||
_drawX = 2
|
||
Else
|
||
_drawX += _drawW + 2
|
||
End If
|
||
|
||
g.FillEllipse(New SolidBrush(_pointResults(index).Color), New Rectangle(_drawX, _drawY, _drawW, _drawW))
|
||
Next
|
||
End Using
|
||
End Sub
|
||
|
||
Private Sub PnlProduct_SizeChanged(sender As Object, e As EventArgs) Handles PnlPoint.SizeChanged
|
||
|
||
End Sub
|
||
|
||
Class PointChartResult
|
||
Property BarCode() As String
|
||
|
||
|
||
Property Result() As Boolean
|
||
|
||
Property Color() As Color
|
||
End Class
|
||
|
||
Private Sub PnlPoint_Paint(sender As Object, e As PaintEventArgs) Handles PnlPoint.Paint
|
||
RedrawPointChart()
|
||
End Sub
|
||
|
||
#End Region
|
||
|
||
#Region "测试执行"
|
||
|
||
Private Sub StartTestEvent()
|
||
'检测
|
||
If TestStatus = TestStatusEnum.Testing Then
|
||
If UtsMsgBox.ShowDialog("当前已处于测试状态中,是否结束测试!", UtsMsgBox.UtsMsgBoxTypeEnum.YesNo, "测试已开启") = DialogResult.OK Then
|
||
StopTest()
|
||
End If
|
||
Return
|
||
End If
|
||
|
||
If TestProcessStation Is Nothing Then
|
||
UtsMsgBox.ShowDialog("请选择测试站再尝试进行测试!")
|
||
Return
|
||
End If
|
||
|
||
If CheckValidDate(TestProcessStation.Packet.ValidDate) = False Then
|
||
UtsMsgBox.ShowDialog("测试功能已超过使用期限,请联系管理员!")
|
||
Return
|
||
End If
|
||
|
||
|
||
If _testThread IsNot Nothing AndAlso _testThread.IsAlive Then
|
||
UtsMsgBox.ShowDialog("测试线程未完全退出,请稍后开始测试!")
|
||
Return
|
||
End If
|
||
|
||
StartTest() '开始测试
|
||
End Sub
|
||
|
||
''' <summary>
|
||
''' 校验测试流程有效日期
|
||
''' </summary>
|
||
''' <returns></returns>
|
||
Private Function CheckValidDate(validDate As Date) As Boolean
|
||
Return Now.CompareTo(validDate) < 0
|
||
End Function
|
||
|
||
''' <summary>
|
||
''' 开始测试
|
||
''' </summary>
|
||
Private Sub StartTest()
|
||
_testThread = New Thread(AddressOf _tester.StartTest)
|
||
_testThread.Start() '开启测试线程
|
||
End Sub
|
||
|
||
|
||
''' <summary>
|
||
''' 终止测试
|
||
''' </summary>
|
||
Private Sub StopTest()
|
||
_tester.ExitTest()
|
||
End Sub
|
||
|
||
#End Region
|
||
|
||
#Region "统一测试模块"
|
||
Private _tester As UtsTester
|
||
|
||
Private Sub InitTester()
|
||
ApplicationLog.WriteInfoLog($"测试器初始化中。")
|
||
_tester = UtsTester.CreateTester()
|
||
|
||
'_tester.TestFailMode = UtsTester.TestFailModeEnum.StepFail
|
||
|
||
AddHandler _tester.TestStart, AddressOf IUtsTest_TestStart
|
||
AddHandler _tester.TestPass, AddressOf IUtsTest_TestPass
|
||
AddHandler _tester.TestFail, AddressOf IUtsTest_TestFail
|
||
AddHandler _tester.TestPause, AddressOf IUtsTest_TestPause
|
||
AddHandler _tester.TestEnd, AddressOf IUtsTest_TestEnd
|
||
|
||
AddHandler _tester.TestStatusChanged, AddressOf IUtsTest_TestStatusChanged
|
||
|
||
AddHandler _tester.TestNodeChanged, AddressOf IUtsTest_TestNodeChanged
|
||
AddHandler _tester.TestNodeCompleted, AddressOf IUtsTest_TestNodeCompleted
|
||
|
||
AddHandler _tester.TestProgressChanged, AddressOf IUtsTest_TestProgressChanged
|
||
AddHandler _tester.RetryProgressChanged, AddressOf IUtsTest_RetryProgressChanged
|
||
|
||
AddHandler _tester.TestTimeChanged, AddressOf IUtsTest_TestTimeChanged
|
||
|
||
AddHandler StationEditStatusMonitor.StationEditStatusChanged, AddressOf _tester.StationEditStatusChanged
|
||
|
||
ApplicationLog.WriteInfoLog($"测试器初始化完成。")
|
||
End Sub
|
||
|
||
Private Sub IUtsTest_TestStart(sender As Object, e As EventArgs) Implements IUtsTest.TestStart
|
||
If _tester.DebugMode Then Return
|
||
If PicStepTip.InvokeRequired Then '判断是否需要开委托
|
||
PicStepTip.Invoke(New Action(Of Object, EventArgs)(AddressOf IUtsTest_TestStart), New Object() {sender, e})
|
||
Return
|
||
End If
|
||
|
||
PicStepTip.Image = TestProcessStation.Packet.StationImage '重置提示图
|
||
_recordGrid.ClearRecode() '清空测试记录项
|
||
|
||
ApplicationLog.WriteInfoLog($"测试页面测试开始。")
|
||
End Sub
|
||
|
||
Private Sub IUtsTest_TestPass(sender As Object, e As EventArgs) Implements IUtsTest.TestPass
|
||
If _tester.DebugMode Then Return
|
||
ApplicationLog.WriteInfoLog($"测试页面测试成功。")
|
||
End Sub
|
||
|
||
Private Sub IUtsTest_TestFail(sender As Object, e As TestFailEventArgs) Implements IUtsTest.TestFail
|
||
If _tester.DebugMode Then Return '调试模式不处理
|
||
UpdateTestNode(e.Node)
|
||
ApplicationLog.WriteInfoLog($"测试页面测试失败。")
|
||
End Sub
|
||
|
||
Private Sub IUtsTest_TestPause(sender As Object, e As TestPauseEventArgs) Implements IUtsTest.TestPause
|
||
If _tester.DebugMode Then Return '调试模式不处理
|
||
UpdateTestNode(e.Node)
|
||
ApplicationLog.WriteInfoLog($"测试页面测试暂停。")
|
||
End Sub
|
||
|
||
Private Sub IUtsTest_TestEnd(sender As Object, e As TestEndEventArgs) Implements IUtsTest.TestEnd
|
||
If _tester.DebugMode Then Return '调试模式不处理
|
||
|
||
If String.IsNullOrWhiteSpace(e.TestResult.DUT_SN) Then
|
||
ApplicationLog.WriteWarningLog($"测试页面测试结束,无SN号不予入库。")
|
||
Return
|
||
End If
|
||
|
||
If e.TestResult.DUT_SN.Length > 32 Then
|
||
ApplicationLog.WriteWarningLog($"测试页面测试结束,过长的SN号[{e.TestResult.DUT_SN}]不予入库。")
|
||
MsgBox($"当前SN号[{e.TestResult.DUT_SN}]超过设定长度上限32,不予录入数据库。")
|
||
Return
|
||
End If
|
||
|
||
|
||
ApplicationLog.WriteInfoLog($"测试页面测试结束处理中,SN:{e.TestResult.DUT_SN},Result:{e.TestResult.TestResult}。")
|
||
|
||
SaveTestLogToCsv(e.TestResult) '保存至CSV
|
||
SaveTestLogToDatabase(e.TestResult) '存储数据至数据库
|
||
|
||
AddBarChart(e.TestResult) '当前时测试总数绘制至图表
|
||
AddPointChart(e.TestResult) '测试结果绘制至点阵图
|
||
AddPieChart(e.TestResult) '测试结果绘制至饼状图
|
||
|
||
|
||
ApplicationLog.WriteInfoLog($"测试页面测试结束。")
|
||
End Sub
|
||
|
||
''' <summary>
|
||
''' 存储单笔测试记录至数据库
|
||
''' </summary>
|
||
Private Sub SaveTestLogToDatabase(result As TestResult)
|
||
If String.IsNullOrWhiteSpace(result.DUT_SN) Then Return '无SN不处理
|
||
Try
|
||
Dim tbName As String = TestLogTable.TableName(TestProcessStation.ParentProject.Index, TestProcessStation.StationID)
|
||
DbConnector.SaveTestLog(tbName, TestProcessStation, result)
|
||
Catch ex As Exception
|
||
ApplicationLog.WriteErrorLog($"保存测试结果至数据库失败:{ex.Message}")
|
||
UtsMsgBox.ShowDialog($"保存测试结果至数据库失败:{ex.Message}")
|
||
End Try
|
||
End Sub
|
||
|
||
|
||
Private Sub IUtsTest_TestNodeChanged(sender As Object, e As TestNodeChangedEventArgs) Implements IUtsTest.TestNodeChanged
|
||
If _tester.DebugMode Then Return
|
||
UpdateTestNode(e.Node)
|
||
End Sub
|
||
|
||
Private Sub UpdateTestNode(node As RowNode)
|
||
If _tester.DebugMode Then Return
|
||
If _tester.TestFiexdModule <> FixedModuleEnum.Main Then Return
|
||
If node.Action = False Then Return
|
||
|
||
If LblTestStep.InvokeRequired Then '判断是否需要开委托
|
||
LblTestStep.Invoke(New Action(Of RowNode)(AddressOf UpdateTestNode), New Object() {node})
|
||
Return
|
||
End If
|
||
|
||
LblTestStep.Text = $"Step : [{node.RowListIndex}] - [{_recordGrid.GetRowByNode(node)}]"
|
||
LblStepTip.Text = $"[{node.RowListIndex}]-{node.ParentNode.Label}:{node.Description}"
|
||
|
||
_recordGrid.UpdateTestRow(node)
|
||
End Sub
|
||
|
||
Public Sub IUtsTest_TestNodeCompleted(sender As Object, e As TestNodeCompletedEventArgs) Implements IUtsTest.TestNodeCompleted
|
||
If _tester.DebugMode Then Return
|
||
_recordGrid.UpdateTestRecord(e.Node, e.TestReturn)
|
||
End Sub
|
||
|
||
Public Sub IUtsTest_TestStatusChanged(sender As Object, e As TestStatusChangedEventArgs) Implements IUtsTest.TestStatusChanged
|
||
If _tester.DebugMode Then Return
|
||
UpdateTestStatus(e.Status)
|
||
End Sub
|
||
|
||
''' <summary>
|
||
''' 根据测试状态,更新界面UI显示
|
||
''' </summary>
|
||
''' <param name="status"></param>
|
||
Private Sub UpdateTestStatus(status As TestStatusEnum)
|
||
If _tester.DebugMode Then Return
|
||
If LblTestStatus.InvokeRequired Then '判断是否需要开委托
|
||
LblTestStatus.Invoke(New Action(Of TestStatusEnum)(AddressOf UpdateTestStatus), New Object() {status})
|
||
Return
|
||
End If
|
||
|
||
Select Case status
|
||
Case TestStatusEnum.WaitForTest
|
||
LblTestStatus.ForeColor = _errCodeManager("9002").Color
|
||
LblTestStatus.Text = $"Wait"
|
||
|
||
ApplicationLog.WriteInfoLog($"测试页面测试状态变更,等待测试。")
|
||
Case TestStatusEnum.Testing
|
||
LblTestStatus.ForeColor = _errCodeManager("9004").Color
|
||
LblTestStatus.Text = $"Testing"
|
||
|
||
ApplicationLog.WriteInfoLog($"测试页面测试状态变更,测试中。")
|
||
Case TestStatusEnum.TestPass
|
||
LblTestStatus.ForeColor = _errCodeManager("9002").Color
|
||
LblTestStatus.Text = $"Pass"
|
||
|
||
ApplicationLog.WriteInfoLog($"测试页面测试状态变更,测试成功。")
|
||
Case TestStatusEnum.TestFail
|
||
LblTestStatus.ForeColor = _errCodeManager("9003").Color
|
||
LblTestStatus.Text = $"Fail"
|
||
|
||
ApplicationLog.WriteInfoLog($"测试页面测试状态变更,测试失败。")
|
||
Case TestStatusEnum.DeviceError
|
||
LblTestStatus.ForeColor = _errCodeManager("9003").Color
|
||
LblTestStatus.Text = $"Error"
|
||
|
||
ApplicationLog.WriteErrorLog($"测试页面测试状态变更,设备错误。")
|
||
Case Else
|
||
Console.WriteLine($"测试页面测试状态变更,未知状态:{status}。")
|
||
|
||
ApplicationLog.WriteErrorLog($"测试页面测试状态变更,未知状态:{status}。")
|
||
End Select
|
||
|
||
LblTestStep.ForeColor = LblTestStatus.ForeColor
|
||
LblStepTip.ForeColor = LblTestStatus.ForeColor
|
||
|
||
If status = TestStatusEnum.Testing Then
|
||
BtnStartTest.Text = $"Stop(&S)" '更新测试按键
|
||
BtnStartTest.ForeColor = Color.OrangeRed
|
||
Else
|
||
BtnStartTest.Text = $"Start(&S)" '更新测试按键
|
||
BtnStartTest.ForeColor = Color.Green
|
||
End If
|
||
End Sub
|
||
|
||
Private Sub IUtsTest_TestTimeChanged(sender As Object, e As TestTimeEventArgs) Implements IUtsTest.TestTimeChanged
|
||
If _tester.DebugMode Then Return
|
||
UpdateTestTime(e.TimeElapsed)
|
||
End Sub
|
||
|
||
''' <summary>
|
||
''' 更新测试时间
|
||
''' </summary>
|
||
''' <param name="elapsed"></param>
|
||
Private Sub UpdateTestTime(elapsed As TimeSpan)
|
||
If StuState.InvokeRequired Then '判断是否需要开委托
|
||
StuState.Invoke(New Action(Of TimeSpan)(AddressOf UpdateTestTime), New Object() {elapsed})
|
||
Return
|
||
End If
|
||
|
||
TssLblTestTime.Text = $"Time:{elapsed.Hours:D2}:{elapsed.Minutes:D2}:{elapsed.Seconds:D2}:{elapsed.Milliseconds:D3}"
|
||
End Sub
|
||
|
||
Private Sub IUtsTest_TestProgressChanged(sender As Object, e As TestProgressChangedEventArgs) Implements IUtsTest.TestProgressChanged
|
||
If _tester.DebugMode Then Return
|
||
UpdateTestProgress(CInt(e.Percent))
|
||
End Sub
|
||
|
||
Private Sub UpdateTestProgress(progress As Integer)
|
||
Try
|
||
If _tester.DebugMode Then Return
|
||
If PrgStepTip.InvokeRequired Then '判断是否需要开委托
|
||
PrgStepTip.Invoke(New Action(Of Integer)(AddressOf UpdateTestProgress), New Object() {progress})
|
||
Return
|
||
End If
|
||
If progress < TssBarTestProgress.Minimum Then progress = TssBarTestProgress.Minimum
|
||
If progress > TssBarTestProgress.Maximum Then progress = TssBarTestProgress.Maximum
|
||
TssBarTestProgress.Value = progress
|
||
Catch ex As Exception
|
||
|
||
End Try
|
||
|
||
End Sub
|
||
|
||
Private Sub IUtsTest_RetryProgressChanged(sender As Object, e As TestProgressChangedEventArgs) Implements IUtsTest.RetryProgressChanged
|
||
If _tester.DebugMode Then Return
|
||
UpdateRetryProgress(CInt(e.Percent))
|
||
End Sub
|
||
|
||
Private Sub UpdateRetryProgress(progress As Integer)
|
||
If _tester.DebugMode Then Return
|
||
If PrgStepTip.InvokeRequired Then '判断是否需要开委托
|
||
PrgStepTip.Invoke(New Action(Of Integer)(AddressOf UpdateRetryProgress), New Object() {progress})
|
||
Return
|
||
End If
|
||
|
||
PrgStepTip.Value = progress
|
||
End Sub
|
||
|
||
|
||
Private Sub IUtsTest_TestCountChanged(sender As Object, e As TestCountChangedEventArgs) Implements IUtsTest.TestCountChanged
|
||
If _tester.DebugMode Then Return
|
||
UpdateTestCount(e.PassCount, e.FailCount)
|
||
End Sub
|
||
|
||
Private Sub UpdateTestCount(pass As Integer, fail As Integer)
|
||
If StuState.InvokeRequired Then '判断是否需要开委托
|
||
StuState.Invoke(New Action(Of Integer, Integer)(AddressOf UpdateTestCount), New Object() {pass, fail})
|
||
Return
|
||
End If
|
||
|
||
TssLblFailCount.Text = $"Fail:{fail}"
|
||
TssLblPassCount.Text = $"Pass:{pass}"
|
||
TssLblTestCount.Text = $"Count:{pass + fail}"
|
||
End Sub
|
||
#End Region
|
||
|
||
#Region "表格相关操作"
|
||
Private Sub InitRecordGrid()
|
||
_recordGrid = New TestRecordGrid() With {.Grid = GrdStepTestRecord}
|
||
End Sub
|
||
|
||
|
||
Private Sub TsmiShowAllRows_Click(sender As Object, e As EventArgs) Handles TsmiShowAllRows.Click
|
||
_recordGrid.ShowAllRows()
|
||
End Sub
|
||
|
||
Private Sub TsmiShowRecordRows_Click(sender As Object, e As EventArgs) Handles TsmiShowRecordRows.Click
|
||
_recordGrid.ShowRecordRows()
|
||
End Sub
|
||
|
||
Private Sub TsmiTestSetupNode_Click(sender As Object, e As EventArgs) Handles TsmiTestSetupNode.Click
|
||
If _tester.ExecuteFixedModule(FixedModuleEnum.Setup).ExecuteResult Then
|
||
UtsMsgBox.ShowDialog($"测试 {FixedModuleEnum.Setup} 模块执行完成!")
|
||
Else
|
||
UtsMsgBox.ShowDialog($"测试 {FixedModuleEnum.Setup} 模块执行失败!")
|
||
End If
|
||
End Sub
|
||
|
||
Private Sub TsmiTestCleanupNode_Click(sender As Object, e As EventArgs) Handles TsmiTestCleanupNode.Click
|
||
If _tester.ExecuteFixedModule(FixedModuleEnum.Cleanup).ExecuteResult Then
|
||
UtsMsgBox.ShowDialog($"测试 {FixedModuleEnum.Cleanup} 模块执行完成!")
|
||
Else
|
||
UtsMsgBox.ShowDialog($"测试 {FixedModuleEnum.Cleanup} 模块执行失败!")
|
||
End If
|
||
End Sub
|
||
|
||
Private Sub TsmiRetryTestNode_Click(sender As Object, e As EventArgs) Handles TsmiTestNode.Click
|
||
Dim node As RowNode = _recordGrid.ActiveNode
|
||
If node Is Nothing Then Return
|
||
|
||
_tester.ExecutePlan(node, Nothing)
|
||
End Sub
|
||
|
||
Private Sub TsmiStartTestWithNode_Click(sender As Object, e As EventArgs) Handles TsmiStartTestWithNode.Click
|
||
Dim node As RowNode = _recordGrid.ActiveNode
|
||
If node Is Nothing Then Return
|
||
|
||
While node IsNot Nothing
|
||
_tester.ExecutePlan(node, Nothing)
|
||
|
||
If node.NextNode Is Nothing Then
|
||
If node.RowLever = 1 Then Exit While
|
||
node = node.ParentNode
|
||
Else
|
||
node = node.NextNode
|
||
End If
|
||
End While
|
||
End Sub
|
||
|
||
Public Sub SetSpcSplitterDistance(Distance As Integer)
|
||
SpcMain.SplitterDistance = Distance
|
||
End Sub
|
||
|
||
Public Function GetSpcSplitterDistance() As Integer
|
||
Return SpcMain.SplitterDistance
|
||
End Function
|
||
|
||
#End Region
|
||
|
||
End Class
|
||
End Namespace |