#=============================================== # TkPW #=============================================== package TkPW; #TkPlotModuleの継承クラスとする use TkPlotModule; @ISA = qw(TkPlotModule); use lib 'd:/Programs/Perl/lib'; use lib 'd:/Programs/Perl/lib2.0'; use lib 'd:/Tsukamoto'; use lib '.'; use strict; use Utils; use MyTk::GraphFrameArray; use GraphData; use Device::Device; my $GratingPort = "COM1"; my $PMeterPort = "COM4"; my $GratingModule = "Cornerstone130"; my $PMeterModule = "Laserstar3APLS"; #============================================================ # コンストラクタ、デストラクタ(お約束) #============================================================ sub new { my ($module, $app, $canvas) = @_; my $this = {}; bless $this; $this->SetApplication($app); return $this; } sub DESTROY { my $this = shift; $this->SUPER::DESTROY(@_); } #============================================================ # 継承クラスで定義しなおすウィンドウ関係メンバー関数 #============================================================ # 以下、標準の動作をしたい場合は、mw()の標準関数を呼び出す # 何もせずにundefを返すと、それぞれのウジェットを作成しない # ウジェット全体の作成 # mw()->InitCreateWidgets()を呼び出した後、 # ウィンドウタイトルを変更している sub CreateWidgets { my ($this) = @_; my $mw = $this->mw(); my $ret = $mw->InitCreateWidgets(); my $Frame = $mw->{'DataClassFrame'}; #データを保存するファイル名を選択する my $Frame0 = $Frame->MyFrame()->pack(-fill => 'x'); $this->{'FileLabel'} = $Frame0->MyLabel( -text => 'Save File:' )->pack(-side => 'left'); $this->{'FileEntry'} = $Frame0->MyEntry( -width => 50, -takefocus => 1, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $this->{'FileEntry'}->focus(); $this->{'FilePathButton'} = $Frame0->MyButton( -text => '&Choose', -takefocus => 1, -command => [ \&ChooseFile, $this, $this->{'FileEntry'} ], )->pack(-side => 'left'); $this->{'FileEntry'}->SetText('c.txt'); #測定インターバルを入力するテキストボックス(Entry) my $Frame1 = $Frame->MyFrame()->pack(-fill => 'x'); $this->{'IntervalLabel'} = $Frame1->MyLabel( -text => 'Interval:' )->pack(-side => 'left', -fill => 'x'); $this->{'IntervalEntry'} = $Frame1->MyEntry( -width => 30, -takefocus => 1, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $this->{'IntervalEntry'}->SetText("500"); $this->{'IntervalUnitLabel'} = $Frame1->MyLabel( -text => 'ms' )->pack(-side => 'left'); #平均を取る回数を入力するテキストボックス(Entry) my $Frame2 = $Frame->MyFrame()->pack(-fill => 'x'); $this->{'nAverageLabel'} = $Frame2->MyLabel( -text => '# of Average:', )->pack(-side => 'left', -fill => 'x'); $this->{'nAverageEntry'} = $Frame2->MyEntry( -width => 5, -takefocus => 1, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $this->{'nAverageEntry'}->SetText(10); $this->{'WRangeLabel1'} = $Frame2->MyLabel( -text => ' Wavelength range:', )->pack(-side => 'left', -fill => 'x'); $this->{'W0Entry'} = $Frame2->MyEntry( -width => 5, -takefocus => 1, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $this->{'W0Entry'}->SetText(600); $this->{'WRangeLabel2'} = $Frame2->MyLabel( -text => ' - ', )->pack(-side => 'left', -fill => 'x'); $this->{'W1Entry'} = $Frame2->MyEntry( -width => 5, -takefocus => 1, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $this->{'W1Entry'}->SetText(2500); $this->{'WRangeLabel3'} = $Frame2->MyLabel( -text => ', Step:', )->pack(-side => 'left', -fill => 'x'); $this->{'WStepEntry'} = $Frame2->MyEntry( -width => 5, -takefocus => 1, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $this->{'WStepEntry'}->SetText(5.0); $this->{'WRangeLabel4'} = $Frame2->MyLabel( -text => ' nm', )->pack(-side => 'left', -fill => 'x'); #Start(Stop)ボタンとClearボタン my $Frame3 = $Frame->MyFrame()->pack(-fill => 'x'); $this->{'StartButton'} = $Frame3->MyButton( -text => 'Start', -takefocus => 1, -command => [ \&StartButton, $this, "Start" ], )->pack(-side => 'left', -fill => 'x'); $this->{'ClearButton'} = $Frame3->MyButton( -text => 'Clear', -takefocus => 1, -command => [ \&StartButton, $this, "Clear" ], )->pack(-side => 'left', -fill => 'x'); #メインウィンドウのタイトルを設定 $mw->SetTitle("P-W measurement / TkPlot"); $this->CreateDevices(); return $ret; } #ファイル選択ペインを作成しない sub CreateSelectFilePane { my ($this) = @_; return undef; } #ファイル内容リストボックス、テキストボックスを作成しない sub CreateFileContentPane { my ($this) = @_; return undef; } # 初期のグラフ枠を作成する # 注:InitCreateGraphFrameArray は アプリケーション起動時に一度しか呼ばれない #   CreateGraphFrame は グラフ描画モジュールで、データファイルの読み込みのたびに呼び出される sub InitCreateGraphFrameArray { my ($this, $canvas) = @_; #引数から$canvasが渡されなかった場合のため、$this->Canvas()を呼び出す $canvas = $this->Canvas($canvas); #TkApplicationオブジェクト my $App = $this->App(); #TkPlotModuleオブジェクト。今回の場合は、TkGPIBTestオブジェクト自身が返る my $pDataArray = $App->TkData(); #Iniファイルの設定からフォントを設定する my $font = $App->{'GraphFrameFont'}; my @font = split(/,/, $font) if($font); #キャンバスの描画幅と高さ my $w = $canvas->width(); my $h = $canvas->height(); #グラフ枠の配列オブジェクトを作り、{'GraphFrameArray'}に格納 my $GraphFrameArray = $this->{'GraphFrameArray'} = new GraphFrameArray($this->mw()); #念のため、グラフ枠の配列オブジェクトにもキャンバスサイズを設定 $GraphFrameArray->SetCanvasSize($w, $h); #グラフ枠を一つ作り、$GraphFrame0に取得 $GraphFrameArray->AddGraphFrame(); my $GraphFrame0 = $GraphFrameArray->GetGraphFrame(0); #Iniファイルの設定からグラフ枠の位置を設定する my $FramePosStr0 = $App->{"GraphFramePosition"}; $GraphFrame0->SetPositionByStr($FramePosStr0); #グラフ枠の目盛りにつける文字列を設定する $GraphFrame0->SetXCaption("X"); $GraphFrame0->SetYCaption('Y'); #グラフ枠の表示範囲を設定する。 $GraphFrame0->SetViewRange(0, 0, 1, 1); #データの配列をつくる my @X; my @Y; # データの配列を$GraphFrame0に結びつける # AddGraphDataには、データ配列のリファレンスを渡す #  0,'black'は、幅 0、色が'black'の線を描く => 線を描かない #  "dot", 1, "red", 0, "red",は、"red"色のdotを描画する #  "XAutoSkip"は、データ量が多いときに、画面の解像度に合わせて描画データをスキップする #  最後の"x","y"は、X,Yデータにつける名前。ほとんど意味はない $GraphFrame0->AddGraphData(\@X, \@Y, 0, 'black', "circle", 3, "red", 0, "red", "XAutoSkip", "x", "y"); return undef; } #======================================================================= # bindされた応答関数 #======================================================================= #ファイル選択ボタンを押したときに呼ばれる sub ChooseFile { my ($this, $widget) = @_; my $fmask = '*.*'; my $defstr = ''; my $message = 'Choose file'; my $dir = ''; my $filepath = Dialog::OpenFileDialog($this->mw(), 'save', $fmask, $defstr, $message, $dir); if($filepath) { if($widget) { $widget->SetText($filepath); } } return $filepath; } #Start, Clearボタンが押されたときに呼ばれる #$actionに、どのボタンが押されたかの情報が入る sub StartButton { my ($this, $action) = @_; my $button = $this->{'StartButton'}; my $text = $button->GetText(); if($action =~ /start/i) { # Startボタンが押されたとき、Startボタンの状態が"Start"か"Stop"に # なっているかによって処理を変える if($text =~ /start/i) { print "Press for Start\n"; $this->PressStart(); $button->SetText("Start"); } elsif($text =~ /stop/i) { print "Press for Stop\n"; $this->PressStop(); } } elsif($action =~ /clear/i) { print "Press for Clear\n"; $this->PressClear(); } } #======================================================================= # 呼び出される関数 #======================================================================= sub CreateDevices { my ($this) = @_; #測定器のオブジェクトを作る $this->{Cornerstone130} = new Device( -Port => $GratingPort, -ModuleName => $GratingModule); $this->{Laserstar3APLS} = new Device( -Port => $PMeterPort, -ModuleName => $PMeterModule); } sub Measure { my ($this) = @_; #"Stop"ボタンがおされると、'DoStop'が1になる。このとき、何もせずに帰る return if($this->{'DoStop'}); my $GraphFrameArray = $this->{'GraphFrameArray'}; my $GraphFrame = $GraphFrameArray->GetGraphFrame(0); my $data = $GraphFrame->GetPlotData(0); #カウンター変数を取得 my $c = $this->{'Count'}; #Start: GPIBシミュレーションルーチン:GPIBでデータを$x,$yに受け取る my ($x, $y) = $this->MeasureByCount($c); #End: GPIBシミュレーションルーチン $data->AddData($x, $y); #データをコンソールに表示 $x = Utils::Round($x, 4); #有効数字を4桁に切り詰める $y = Utils::Round($y, 4); #有効数字を4桁に切り詰める print "$c: ($x,$y)\n"; #データをファイルに書き込む if($this->{'OutFileClass'}) { $this->{'OutFileClass'}->Write("$c\t$x\t$y\n"); } #データと$GraphFrameの最大・最小値を更新 $data->CalMinMax(); $GraphFrame->CalMinMax(); #データの範囲にあわせて$GraphFrameの描画範囲を変えたい場合 $GraphFrame->AdjustViewRange(0.05, 0.05, 0.05, 0.05); #再描画 $this->Draw(); $this->mw()->update; #カウンター変数を更新 $this->{'Count'} += 1; } #実際の測定ルーチン sub MeasureByCount { my ($this, $count) = @_; my $Interval = $this->{'IntervalEntry'}->GetText() / 1000.0; # in seconds my $x = $this->{WStart} + $this->{WStep} * $count; $this->{Cornerstone130}->GoWave($x); Utils::sleep($Interval); my $y = $this->{Laserstar3APLS}->Measure($x); return ($x, $y); } sub PressStart { my ($this) = @_; my $button = $this->{'StartButton'}; #ファイル名を取得し、すでに存在するかどうかをチェック my $FileName = $this->{'FileEntry'}->GetText(); #ファイル名が選択されていないときは、メッセージを出して処理を中止 if(!$FileName) { $this->mw()->messageBox( -icon => "info", # "info" "warning" "question" -type => "Ok", # "YesNo" "YesNoCancel" "OkCancel" "RetryCancel" -title => 'Error on FileName', -message => "FileName is not selected.\nChoose it."); return undef; } #ファイルが存在するときは、上書きの確認 if(-e $FileName) { my $ret = $this->mw()->messageBox( -icon => "question", # "info" "warning" "question" -type => "YesNo", # "YesNo" "YesNoCancel" "OkCancel" "RetryCancel" -title => 'Confirm for overwrite', -message => "$FileName exists.\nOverwrite?"); return unless($ret eq 'Yes'); } $this->{nAverage} = $this->{nAverageEntry}->GetText(); my $WStart = $this->{WStart} = $this->{W0Entry}->GetText(); my $WEnd = $this->{WEnd} = $this->{W1Entry}->GetText(); my $WStep = $this->{WStep} = $this->{WStepEntry}->GetText(); my $nWStep = $this->{nWStep} = int( ($WEnd - $WStart) / $WStep + 1.0000001 ); $this->{Cornerstone130}->Initialize(); $this->{Laserstar3APLS}->Initialize(); $button->SetText("Stop"); $this->{'DoStop'} = 0; $this->{'Count'} = 0; #ファイルを書き込みようにオープンする $this->{'OutFileClass'} = new JFile($FileName, "w"); if(!$this->{'OutFileClass'}) { $this->mw()->messageBox( -icon => "info", # "info" "warning" "question" -type => "Ok", # "YesNo" "YesNoCancel" "OkCancel" "RetryCancel" -title => 'Error', -message => "Can not write to $FileName."); return undef; } # データの読み込みをループ処理で行うと、ボタンの更新などができないので、 # タイマー(mw()->after())を使って$itime ms後にMeasure()関数を呼び出す # my $itime = $this->{'IntervalEntry'}->GetText(); for(my $i = 0 ; $i < $nWStep ; $i++) { # Stopボタンが押されると、{'DoStop'}が1になる last if($this->{DosStop}); $this->Measure(); } if($this->{'OutFileClass'}) { $this->{'OutFileClass'}->Close(); delete $this->{'OutFileClass'}; } } sub PressClear { my ($this) = @_; my $GraphFrameArray = $this->{'GraphFrameArray'}; my $GraphFrame = $GraphFrameArray->GetGraphFrame(0); my $data = $GraphFrame->GetPlotData(0); $data->ClearAll(); $GraphFrame->CalMinMax(); $this->Draw(); } # {'DoStop'}に1を入れて、測定ループを終了する sub PressStop { my ($this) = @_; $this->{'DoStop'} = 1; } 1;