Delphi XE5 で Canon ケーブルIDプリンター MK2500 を使う
一応プリンターなので、Delphi からでも使えます。が、あまり使い勝手が良いとは言えません。
本体の編集文字や設定とはまったく別に動くことが、何かのメリットになるのかも。(^^;
(製品に同梱されているツールの使い勝手も、お世辞にも良いとは言えません)
MK2500 本体の編集窓部分に、文字列を転送するのではなく、プリンターとしてラベル、チューブ... に描画する使い方になります。
フォントは、MK2500 のフォントではなく、Windows のフォントになります。
※プリンタ情報の取得、設定については、Mr.Xray さんのサイトを参考にさせていただきました。m(_"_)m
エクセルからのコピーペーストを想定して、一行の文字列中にタブがあれば、2行で印字するようにしています。
今のところ、連番には未対応 ... です。
カット長(用紙長)の設定がサポートされていないようなので、プロパティウィンドウを表示させて、その部分を別スレッドから無理やり書き換えています。
なので、一瞬、プロパティウィンドウが表示されます。
unit mk2500Unit2; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Printers, Vcl.StdCtrls,WinSpool, Vcl.ExtCtrls; type TForm2 = class(TForm) Memo1: TMemo; ComboBox2: TComboBox; Label1: TLabel; Edit1: TEdit; Button3: TButton; Edit2: TEdit; Label2: TLabel; procedure FormCreate(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; var Form2: TForm2; implementation {$R *.dfm} uses mk2500Unit3; procedure TabTextToSL(const atext: string; sl: TStrings); var n : integer; s : string; begin sl.Clear; s := atext; n := Pos(#09, s); while n > 0 do begin sl.Add(Copy(s, 1, n - 1)); Delete(s, 1, n); n := Pos(#09, s); end; if Trim(s) <> '' then sl.Add(s); end; procedure TForm2.Button3Click(Sender: TObject); var ADevice : array [0..255] of Char; ADriver : array [0..255] of Char; APort : array [0..255] of Char; pDevMode : PDeviceModeW; PaperLength : SmallInt; PaperSize : SmallInt; ADeviceMode: THandle; hPrinter : THandle; Mode : Cardinal; ret : integer; i : integer; ytop, xleft, txtH : integer; sl : TStringList; begin ret := 0; PaperLength := Trunc(StrToFloatDef(Edit1.Text, 0) * 10); with ComboBox2 do begin if ItemIndex >= 0 then PaperSize := SmallInt(Items.Objects[ItemIndex]) else PaperSize := 0; end; if (PaperLength > 0) and (PaperSize > 0) then begin // プリンターを MK2500 に Printer.PrinterIndex := Printer.Printers.IndexOf('MK2500'); hPrinter := 0; // 現在のプリンタに関する情報を取り出す Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode); // 初期化 Printer.SetPrinter(ADevice, ADriver, APort, 0); // 対象のプリンタ情報 Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode); if (ADeviceMode > 0) then begin // プリンタ情報のアドレスを取得 pDevMode := GlobalLock(ADeviceMode); try // 対象のプリンタのハンドルを取得 if OpenPrinter(ADevice, hPrinter, nil) then begin try // カット長の設定のためにスレッド生成 Tmk2500edit.Create(Edit1.Text); if (pDevMode^.dmFields and DM_PAPERSIZE) <> 0 then pDevMode^.dmPaperSize := PaperSize; // ※PAPERLENGTH はサポートされていない if (pDevMode^.dmFields and DM_PAPERLENGTH) <> 0 then pDevMode^.dmPaperLength := PaperLength; if (pDevMode^.dmFields and DM_COPIES) <> 0 then pDevMode^.dmCopies := 1; Mode := DM_IN_PROMPT or DM_OUT_BUFFER or DM_IN_BUFFER; // MK2500 のプロパティダイアログを表示 // 別スレッドから自動で閉じられる ret := DocumentProperties(Handle, hPrinter, ADevice, pDevMode^, pDevMode^, Mode); finally // プリンターを閉じる ClosePrinter(hPrinter); end; end; finally // ロック解除 GlobalUnLock(ADeviceMode); end; // 設定を反映 Printer.SetPrinter(ADevice, ADriver, APort, ADeviceMode); end; if ret = 1 then begin with Printer do begin // Canvas.Font.Name := 'MS ゴシック'; Canvas.Font.Size := 10; txtH := Canvas.TextHeight('A'); sl := TStringList.Create; try // 転送開始 BeginDoc; for i := 0 to Memo1.Lines.Count - 1 do begin if i > 0 then NewPage; TabTextToSL(Memo1.Lines[i], sl); if sl.Count = 1 then begin // センタリングのための開始 Y 座標 ytop := (PageHeight - txtH) div 2; // センタリングのための開始 X 座標 xleft := (PageWidth - Canvas.TextWidth(sl[0])) div 2; if xleft < 0 then xleft := 0; // 文字列描画 Canvas.TextOut(xleft, ytop, sl[0]); end else if sl.Count >= 2 then begin // 2行印字 ytop := PageHeight div 2 - txtH + 2; xleft := (PageWidth - Canvas.TextWidth(sl[0])) div 2; if xleft < 0 then xleft := 0; Canvas.TextOut(xleft, ytop, sl[0]); ytop := PageHeight div 2 - 2; xleft := (PageWidth - Canvas.TextWidth(sl[1])) div 2; if xleft < 0 then xleft := 0; Canvas.TextOut(xleft, ytop, sl[1]); end; end; EndDoc; finally sl.Free; end; end; end; end; end; procedure TForm2.FormCreate(Sender: TObject); var ADevice : array [0..255] of Char; ADriver : array [0..255] of Char; APort : array [0..255] of Char; ADeviceMode : THandle; Count : Integer; // 動的配列 PaperNames : array of array [0..63] of Char; PaperNumbers : array of WORD; i : integer; s : string; begin // 現在のプリンタを MK2500 にする Printer.PrinterIndex := Printer.Printers.IndexOf('MK2500'); // 現在のプリンタに関する情報を取り出す Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode); // そのプリンタ 用紙名の数を取得 Count := DeviceCapabilities(ADevice, APort, DC_PAPERNAMES, nil, nil); // その分だけ用紙名配列の長さと用紙番号の配列の長さを確保 SetLength(PaperNames, Count); SetLength(PaperNumbers, Count); // その配列に用紙名と用紙番号を取得 DeviceCapabilities(ADevice, APort, DC_PAPERNAMES, PChar(PaperNames), nil); DeviceCapabilities(ADevice, APort, DC_PAPERS, Pointer(PaperNumbers), nil); // 用紙名をコンボボックスに追加 if Count > 0 then begin for i := 0 to Count - 1 do begin s := String(PaperNames[i]); if s <> '' then //用紙名と用紙番号を格納 ComboBox2.Items.AddObject(s, TObject(PaperNumbers[i])); end; ComboBox2.ItemIndex := 1; end; end; end.
// スレッド部分 unit mk2500Unit3; interface uses System.Classes,Winapi.Windows, Winapi.Messages, System.SysUtils; type Tmk2500edit = class(TThread) private { Private 宣言 } sLen : string; protected procedure Execute; override; public constructor Create(PaperLength : string); end; implementation uses mk2500Unit2; var // mk2500 長さ設定のエディットウィンドウ mkedHwnd: Hwnd; constructor Tmk2500edit.Create(PaperLength : string); begin // カット長 sLen := PaperLength; // 生成と同時にスレッドを実行 inherited Create(False); FreeOnTerminate := True; end; { Tmk2500edit } // プロパティウィンドウの長さ設定の Edit ウィンドウを探す // 最初に見つかったクラス名'Edit'で終了 function EnumWindowProcEditWin(h: HWND; lp: LPARAM):Bool; stdcall; var ClassName : array [0..255] of Char; begin Result := True; //クラス名を取得 GetClassName(h, ClassName, 255); if Classname = 'Edit' then begin mkedHwnd := h; Result := False; end; end; procedure Tmk2500edit.Execute; var hmk : HWND; s : string; i : integer; begin while not Terminated do begin Sleep(100); // プロパティ設定ダイアログを探す hmk := FindWindow(nil, 'MK2500のプロパティ'); if hmk <> 0 then begin // オーナーが Form2 であれば if GetWindow(hmk, GW_OWNER) = Form2.Handle then begin // ウィンドウが完成するまで待つ (必須) Sleep(100); // 子ウィンドウを探す EnumChildWindows(hmk, @EnumWindowProcEditWin, 0); if IsWindow(mkedHwnd) then begin s := 'A' + sLen; //文字の送信 for i := 1 to Length(s) do //1文字送る SendMessage(mkedHwnd, WM_CHAR, Word(s[i]), 0); // アクティブに SetForegroundWindow(hmk); // ちらっと見せる Sleep(100); //[Enter]キーを離す keybd_event(VK_RETURN, 0, 0, 0); //[Enter]キーを離す keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0); // keybd_event(VK_ESCAPE, 0, 0, 0); // keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0); end; // スレッド終了 break; end; end; end; end; end.