Visual Basicで画像の上書き保存
Visual Basicの画像関連でのエラー。品物のリストをデータベースに格納する画面を作っていたのですが、画像ファイルはデータベースに格納せずに所定のフォルダに品物のナンバーをファイル名にして保存するようにしていました。
ListBoxで品物を選択すると、画像ファイルがあればPictureBox1に表示する。新しい画像を登録するときには参照ボタンをクリックして画像を選択します。登録ボタンを押すと、PictureBox1の画像を所定のフォルダへ保存します。
ところが、ある条件でエラーが出ます。No.4の品物を表示し、画像を変えて4番の情報を更新するなど、画像を表示して同じ番号で上書きする時だけGDI+がどうとかエラーが出ます。
ん?なんか、どこかで読んだ覚えがあるぞ。記憶をたどりに「vb picturebix 保存 上書き」で検索して、以前見たこちらを読み直す。
ShiroYuki_Mot の ひとりごと: VB 表示した画像ファイルの上書き保存
>GDI+ で ... の エラー メッセージ と ご対面。
画像を開いて、編集して上書き保存するとエラーが出るという話でした。その時は自分で作る物は編集して上書きじゃないから、いいや。と思ったのですが、よくよく考えたら上書きするケースがあったという落ちです。GDI+と上書きが頭に残ってたので、すぐ気づけて良かったです。
改めてソースを追ってみると・・・・。なるほど、ファイルストリームを使って、画像ファイルはすぐにクローズする。画像ファイルは解放されているので、上書き保存が出来るようになるということか。
>きっと、次には 忘れていますよ。 きっと。
参考記事の方もこう書かれていますが、きっと忘れそうなのでブログに残しておきます。残したことすら忘れてしまったりして。
Visual Basicでサービス作成 NC死活監視
NC装置の死活監視機能を作ろうと思いました。
・サービスで常駐
・cnc_allclibhndl3(ハンドル番号取得)コマンドを定期実行し、日時とリターンコードをCSVファイルに追記していく
フォームアプリケーションは作りましたが、サービスは初めてなので、まずはサービスの作り方から調べました。新規プロジェクト作成で、Windowsサービスで作成すればサービスを作れます。
タイマーをフォームアプリケーションと同じように作ったところ、繰り返してくれない・・・・。よく見るとSystem.Windows.Form.Timerって書いてある。フォーム用のタイマーだからサービスでは動かないのでは?と調べてみたらサービスの場合はSystem.Timers.Timerで作らないといけないようです。プログラムの書き方も違いました。
プロパティではEnable=Falseにしておき、サービス開始処理の中で有効化する。その時にインターバルも指定。
Timer1.Enabled = True
Timer1.Interval = 10000
タイマーの中の処理で、今の日時、カンマ、cnc_allclibhndl3のリターンコードを文字列にしたもの、改行を出力。
str1 = System.DateTime.Now & "," & nRet.ToString & vbCrLf
System.IO.File.AppendAllText("C:\XXXX\XXXX\alive.csv", str1)
あと、サービスはVisual Studioからデバッグしても実行できません。Windowsのサービスに登録して、サービスの開始をして実行します。
出来上がったので実機確認。サービスを起動してNCルーターの電源をオン。CSVの前半はNCが起動していないのでリターンコード-16、途中から通信できてリターンコード0に変わりました。
CSVファイルに書くことが出来たので、このデータを使えば何時から何時まで稼働していたか、電源ON・OFFの比率など集計が出来ます。
今回作った機能では電源が入っているかしかわかりません。切削加工していた時間も記録できるようにしたいですね。
FANUC社 FOCAS2ライブラリ
PCとFANUC社のNC装置の間で情報取得・命令実行などを行うFOCAS2というライブラリがあります。これを使って、NC装置の操作盤を使わず、PC上の操作で工作機械を動かすソフトを開発しています。SHODA CNC PROTOCOL、略称SCPです。
FOCAS2の開発に関する情報がネット上で全然ないので、備忘録も兼ねてブログに書いてみようかと思いました。
開発言語はVisual Basicです。Visual Studio 2019を使っています。時代はC#かな、とも思うのですが、サンプルプログラムがVBなのでVBで開発しています。
当初、設計してプログラム作成は外注という話だったのですが、結局自分でプログラムを作っています。とりあえず一通り動くプロトタイプまで1人で作って、エラー処理等の異常系処理やテスト・デバッグはVBのプロに手伝ってもらおうと思っています。
Excelにバーコード入力したくなって、perlでプログラム書いちゃった
Excelにバーコード入力をする場合、1つ読んだら下に移動(Enter入力)か右に移動(Tab入力)しか出来なさそうです。
社員番号と注文番号を交互に読んで、
社員番号 注文番号
1111 1
2222 2
こんな風にしたいのですが。で、考えました。
バーコード 社員番号 注文番号
1111 =A2 =A3
1 =A4 =A5
2222
2
A列に社員番号と注文番号を交互に読んでいき、参照させれば良いのでは。
参照して、下のようになる。
バーコード 社員番号 注文番号
1111 1111 1
1 2222 2
2222
2
予想通りになりました。しかし、規則性があるのでExcelのオートフィル機能でB列はA2、A4、A6・・・とやってくれるかと思ったら、出来ませんでした。
手打ちで書くとなると、果てしなくめんどくさい。社員200人くらいまで大丈夫な物を作るとなると400セルも打つことに。
んー、プログラムでCSVファイル書き出せばいいんじゃない?と思い、perlで書いてみました。
ソース
my $count;
$count = 1;
while ($count < 400){
print ",=\$A\$$count,";
$count ++;
print "=\$A\$$count\n";
$count ++;
}
解説
my $count;
$count = 1;
while ($count < 400){ iが400になるまで繰り返す
print ",=\$A\$$count,"; 初回で,=$A$1を書く。A列を空白にするため、先頭に,がある。
$count ++;
print "=\$A\$$count\n"; 初回で,=$A$2と改行コードを書く。
$count ++;
}
実行してCSVファイルにリダイレクトしてファイル出力する。
出来たCSVファイルの中身。
,=$A$1,=$A$2
,=$A$3,=$A$4
・・・・・
,=$A$399,=$A$400
このCSVを元に、VLOOKUPとCOUNTIFを使って集計し、当日分の注文書を作成、マクロで値貼り付けをして月間注文を集計するシートも作りました。長くなるのでExcelの内容は割愛。気が向いたら後日書きます。
cnc_rdzofsr G54~G59 加工位置オフセットの読み込み
NC装置で加工位置の座標設定があります。X、Y座標が設定されていて、NCプログラムでG54へ行け、と命令するとその座標まで主軸が移動します。そこを加工原点として切削をするのです。
SCPのソフトから、現在設定されている座標の読み込み、ソフト上で値を書き換えてNC装置へ書き込んで設定変更する機能を開発しました。
cnc_rdzofsrで現在の値をNC装置から読み取ります。読み込んでみると、負の数(マイナス)の時に変な数字になっていることに気づきました。4293967296と非常に大きな数字です。
マイナスでおかしい、座標の値は整数型(LONG)・・・・・2の補数表現じゃないか?整数型でマイナスを表現する手法です。大学で習って、その後も数回、何かの勉強で名前は出てきただけで使ったことないのによく思い出したと自分でも感心します。
パソコンの電卓を起動して、256*256*256*256=4294967296
読み込んだ座標がNCの画面上で1000.000mm、FOCASでは整数型で扱うために1000倍した値、つまりnm単位で整数でやりとりします。なので座標は-1000000。
4294967296-1000000を計算してみると・・・・。4293967296、FOCASで読み取った値と一致しました。やはり2の補数表現でした。
ということは、値が2147483648より大きければ負の数なので、IFで分岐してマイナスの値を計算する処理を入れればOK。
ちなみにFOCASの関数仕様書には2の補数表現のことは書いてなかったです。マイナスがあって整数型なんだから気付いて当然と思っているのでしょうか・・・。恐ろしい。あ、どこか全体の説明で書いてあるのかな?関数仕様書じゃない資料に。
Visual Basicでビット演算
FOCAS2でR領域の読み書きをするために、VBでビット演算をする必要がありました。いきなり本物のプログラムにビット演算のプログラムを埋め込むのは大変なので、検証用にビット演算ツールを作ってみました。
VBでビット演算をするには、16進数で論理演算をします。
ビットを立てる→立てたいビットだけ1のマスクとORを取る
ビットを消す→消したいビットだけ0のマスクとANDを取る
元データの2進数、マスクの2進数をそれぞれ10進数と16進数に変換する機能、16進数でANDとORを計算し、計算結果を10進数と2進数に変換する機能を作りました。いくつか試してみたところ、ちゃんと出来てるようなので、これを参考に本物のプログラムにビット演算を入れました。
プログラムの主要部分
2進数→10進数と16進数に変換してテキストボックスに表示
TextBox9.Text = TextBox1.Text * 128 + TextBox2.Text * 64 + TextBox3.Text * 32 + TextBox4.Text * 16 + TextBox5.Text * 8 + TextBox6.Text * 4 + TextBox7.Text * 2 + TextBox8.Text * 1
TextBox10.Text = Hex(TextBox9.Text)
元データとマスクのANDとORを取った結果をテキストボックスに表示
TextBox29.Text = "&H" + TextBox10.Text Or "&H" + TextBox20.Text
TextBox30.Text = "&H" + TextBox10.Text And "&H" + TextBox20.Text
TextBox21.Text = Convert.ToString(Integer.Parse(TextBox29.Text), 2)
TextBox22.Text = Convert.ToString(Integer.Parse(TextBox30.Text), 2)