Windows10になって、いちばん困ったのはプリンタの管理方法の変化だった。デフォルト設定で、最後に使ったプリンタが通常使うプリンタと見なされるようになってから、職場のあちこちで「印刷ができない!」という声が上がることが多くなった。駆け付けてみると、出力先プリンタはいつも「Microsoft Print to PDF」みたいな・・・。
procedure TForm1.Button1Click(Sender: TObject);
var
Ret:string;
begin
if InputQuery('InputQuery', '値を入力:', Ret) then
begin
//OKボタンがクリックされた時
end else begin
//キャンセルボタンがクリックされた時(ESCキーで閉じた場合もFalseになる)
end;
end;
Private Sub CommandButton1_Click()
Dim PrintNo1 As Integer
Dim PrintNo2 As Integer
Dim i As Integer
If UserForm1.TextBox1.Text = "" Then
MsgBox ("開始番号を半角数字で入力してください。")
TextBox1.SetFocus
Exit Sub
End If
If UserForm1.TextBox2.Text = "" Then
MsgBox ("終了番号を半角数字で入力してください。")
TextBox2.SetFocus
Exit Sub
End If
PrintNo1 = UserForm1.TextBox1.Text
PrintNo2 = UserForm1.TextBox2.Text
i = PrintNo1
For i = PrintNo1 To PrintNo2
Range("A2").Select
ActiveCell.FormulaR1C1 = i
Range("B6:AB38").Select
ActiveSheet.PageSetup.PrintArea = "$B$6:$AB$38"
ActiveWindow.SelectedSheets.PrintOut Copies:=1, Collate:=True
Next i
Range("A2").Select
End Sub
Private Sub CommandButton2_Click()
'キャンセルボタンがクリックされた場合
Unload UserForm1
Exit Sub
End Sub
//Formのメンバーにはしていません。
//名前は MyInputQuery に変更
function MyInputQuery(const ACaption, APrompt: string;
var Value: string): Boolean;
var
Form: TForm;
Prompt: TLabel;
Edit: TEdit;
DialogUnits: TPoint;
ButtonTop, ButtonWidth, ButtonHeight: Integer;
function GetAveCharSize(Canvas: TCanvas): TPoint;
var
I: Integer;
Buffer: array[0..51] of Char;
begin
for I := 0 to 25 do Buffer[I] := Chr(I + Ord('A'));
for I := 0 to 25 do Buffer[I + 26] := Chr(I + Ord('a'));
GetTextExtentPoint(Canvas.Handle, Buffer, 52, TSize(Result));
Result.X := Result.X div 52;
end;
begin
Result := False;
Form := TForm.Create(Application);
with Form do begin
try
Canvas.Font := Font;
DialogUnits := GetAveCharSize(Canvas);
BorderStyle := bsDialog;
Caption := ACaption;
ClientWidth := MulDiv(180, DialogUnits.X, 4);
Position := poScreenCenter;
Prompt := TLabel.Create(Form);
with Prompt do
begin
Parent := Form;
Caption := APrompt;
Left := MulDiv(8, DialogUnits.X, 4);
Top := MulDiv(8, DialogUnits.Y, 8);
Constraints.MaxWidth := MulDiv(164, DialogUnits.X, 4);
WordWrap := True;
end;
Edit := TEdit.Create(Form);
with Edit do
begin
Parent := Form;
Left := Prompt.Left;
Top := Prompt.Top + Prompt.Height + 5;
Width := MulDiv(164, DialogUnits.X, 4);
MaxLength := 255;
Text := Value;
SelectAll;
//Password入力用にInputQueryを使用するための設定(Password Mask)
//EditコントロールではPasswordCharに設定した文字が
//入力した文字の代わりに表示される(デフォルトは'#0')
//パスワードマスクするなら
//PasswordChar:= '*';
//これでマスクしなくなる('#0'として文字列化しないこと)
PasswordChar := #0;
//Delphi2009からTEditにNumbersOnlyプロパティ(数字だけを入力可能にする)が
//実装されているそうなので、せっかくだからTrueにしてみた!
//全角文字の「123」も「数値である」と判断してくれます・・・
NumbersOnly := True;
//IMEは使用不可(この1行がどうしても書きたかった!)
ImeMode := imDisable;
//文字位置
//Alignment := taCenter;
Alignment := taLeftJustify;
//Alignment := taRightJustify;
end;
ButtonTop := Edit.Top + Edit.Height + 15;
ButtonWidth := MulDiv(50, DialogUnits.X, 4);
ButtonHeight := MulDiv(14, DialogUnits.Y, 8);
with TButton.Create(Form) do
begin
Parent := Form;
Caption := 'OK';
ModalResult := mrOk;
Default := True;
SetBounds(MulDiv(38, DialogUnits.X, 4), ButtonTop, ButtonWidth,
ButtonHeight);
end;
with TButton.Create(Form) do
begin
Parent := Form;
Caption := 'キャンセル';
ModalResult := mrCancel;
Cancel := True;
SetBounds(MulDiv(92, DialogUnits.X, 4), Edit.Top + Edit.Height + 15,
ButtonWidth, ButtonHeight);
Form.ClientHeight := Top + Height + 13;
end;
if ShowModal = mrOk then
begin
Value := Edit.Text;
Result := True;
end;
finally
Form.Free;
end;
end;
end;
このInputQueryをボタンクリックで呼び出します。
procedure TForm1.Button1Click(Sender: TObject);
var
Ret:string;
begin
if MyInputQuery('Dialog Caption', 'Please Enter the number:', Ret) then
begin
ShowMessage('Entered: '+ Ret);
end else begin
ShowMessage('False!');
end;
end;
var
i, j, k:integer;
begin
//初期化
k:=0;
//合計点を計算
for i := 1 to StringGrid1.RowCount-1 do
begin
for j := 1 to ( 解答欄の数 ) do
begin
if StringGrid1.Cells[j,i] <> '' then
begin
k := K + StrToInt(StringGrid1.Cells[j, i]);
end;
end;
//StringGrid.Cells[列, 行]
StringGrid1.Cells[( 解答欄の数 ) + 1, i]:= IntToStr(k);
//初期化
k:=0;
end;
実は少し工夫すれば100まできちんと表示できます。以前、どこかWeb上の情報で知ったのですが、Loopの中で増加する i の値をそのままProgressBarのPositionに代入せず、現在の i 値より「1大きな値をまず代入」し、その後、「1小さい値をセットしなおす」という技です。どなたが考えた技か知りませんが、これで100まできちんと表示できます。以下に、そのコードを示します(赤文字が追加するコード)。
procedure TForm1.Button1Click(Sender: TObject);
var
i, j:integer;
begin
//表示
StatusBar1.SimpleText:= '進捗状況:';
//ProgressBarの設定
ProgressBar1.Visible:=True;
ProgressBar1.Position:=0;
ProgressBar1.Max:=100;
//初期化
j:= 0;
for i:= 0 to 100 do
begin
//ProgressBar1.Position:= i; // -> MAXまで表示されない
// 100まで表示するコード
inc(j);
If ProgressBar1.Position < ProgressBar1.Max Then
begin
//目的の値より一つ大きくしてから、目的の値にする
ProgressBar1.Position:= j + 1;
ProgressBar1.Position:= j;
end else begin
//最大値にする時
//最大値を1つ増やしてから、元に戻す
ProgressBar1.Max:= 100 + 1;
ProgressBar1.Position:= j + 1;
ProgressBar1.Max:= 100;
ProgressBar1.Position:= j;
end;
Sleep(25);
Application.ProcessMessages;
end;
ProgressBar1.Visible:= False;
ShowMessage('Done!');
end;
StatusBar1DrawPanel手続きの if Panel=StatusBar.Panels[1] then 部分にもProgressBarに関する処理を追加します(赤文字の部分)。
if Panel=StatusBar.Panels[1] then
begin
//文字の表示(このPanel内のみ有効となるようだ)
StatusBar1.Canvas.Font.Color:= clBlack;
//背景色(このPanel内のみ有効となるようだ)
StatusBar1.Canvas.Brush.Color:= clBtnFace;
//矩形を取得
ARect:= Rect;
//表示位置(左寄せ)
DrawText(StatusBar1.Canvas.Handle, PChar(Panel.Text), -1, ARect,
DT_LEFT or DT_VCENTER or DT_SINGLELINE);
//ProgressBarの位置を設定
With ProgressBar1 do begin
Top:=Rect.Top;
Left:=Rect.Left;
Width:=Rect.Right - Rect.Left - 15;
Height:=Rect.Bottom - Rect.Top;
end;
end;
procedure TForm1.Button3Click(Sender: TObject);
var
w:integer;
begin
if not boolInfo then
begin
//制御用フラグを既読扱いに設定
boolInfo:=True;
StatusBar1.Panels[1].Text:= '最初の1回だけは表示したい案内';
//OKボタンを表示する位置を設定
w:= StatusBar1.Canvas.TextWidth('最初の1回だけは表示したい案内');
btnOK.SetBounds(
StatusBar1.Panels[0].Width + w + 5, 0, 40, StatusBar1.ClientHeight);
btnOK.Visible:=True;
StatusBar1.Refresh;
end;
end;
FormCreate手続きに追加する処理です。
procedure TForm1.FormCreate(Sender: TObject);
var
w:integer;
begin
・・・ 省略 ・・・
//案内表示の制御用フラグ
boolInfo:= False;
//OKボタン
btnOK.Parent:= StatusBar1;
btnOK.Visible:= False;
end;
StatusBar1DrawPanel手続きの中の if Panel=StatusBar.Panels[1] then の内容を次のように変更します。
if Panel=StatusBar.Panels[1] then
begin
//文字の表示(このPanel内のみ有効となるようだ)
if not boolInfo then
begin
StatusBar1.Canvas.Font.Color:= clBlack;
end else begin
StatusBar1.Canvas.Font.Color:= clBlue;
end;
//背景色(このPanel内のみ有効となるようだ)
if not boolInfo then
begin
StatusBar1.Canvas.Brush.Color:= clBtnFace;
end else begin
StatusBar1.Canvas.Brush.Color:= clAqua;
end;
・・・ 省略 ・・・
end;
if Ord(Key)=VK_RIGHT then
begin
if ActiveControl is TStringGrid then
begin
if TStringGrid(ActiveControl).EditorMode then
begin
Key:=#0;
//Exit;
end;
end;
end;
if Ord(Key)=VK_RIGHT then
begin
if ActiveControl is TStringGrid then
begin
if TStringGrid(ActiveControl).EditorMode then
begin
ShowMessage('VK_RIGHT');
Key:=#0;
//Exit;
end;
end;
end;
type
・・・
//Col毎のIMEの制御
type
_TGrid = class(TCustomGrid);
private
{ Private 宣言 }
・・・
procedure TFormCollaboration.StringGrid1GetEditText(Sender: TObject; ACol,
ARow: Integer; var Value: string);
begin
//IMEの制御
with TEdit(_TGrid(Sender).InplaceEditor) do
begin
ImeMode := imDisable; //日本語入力OFFは imDisable
end;
end;
【Enterキーでカーソルは下のセルへ移動】
procedure TFormCollaboration.FormKeyPress(Sender: TObject; var Key: Char);
begin
//[Enter]キーでコントロールを移動
//StringGridは編集可能にFormCreateで設定しておく
//->忘れるとセルの移動にEnter×2回必要!
//この方法を使う時はKeyPreview:=True;をFormCreateで指定。
if Ord(Key)=VK_RETURN then
begin
if ActiveControl is TStringGrid then
begin
if TStringGrid(ActiveControl).EditorMode then
begin
//VK_TABではカーソルがレコードの項目を右へ移動。
//ActiveControl.Perform(WM_KEYDOWN,VK_TAB,0);
//VK_DOWNにすると同じ項目の次のレコードへ移動。
ActiveControl.Perform(WM_KEYDOWN,VK_DOWN,0);
Key:=#0;
end;
end else begin
SelectNext(ActiveControl,True,True);
Key:=#0;
end;
end;
end;
【列の非表示】※StringGridの初期化時と採点欄の切り替え時の両方に設定
//列幅の自動調整(やるなら列の非表示設定の前に実行)
for iCOL := 0 to StringGrid1.ColCount-1 do
begin
MaxColWidth := 0;
for iROW := 0 to StringGrid1.RowCount-1 do
begin
TmpColWidth := Canvas.TextWidth(StringGrid1.Cells[iCOL,iROW])+10;
if MaxColWidth < TmpColWidth then
begin
MaxColWidth := TmpColWidth;
end;
end;
StringGrid1.ColWidths[iCOL] := MaxColWidth;
end;
//必要な列のみ表示
for i := 1 to StringGrid1.ColCount-1 do
begin
if i<>StrToInt(ComboBox1.Text) then
begin
StringGrid1.ColWidths[i]:=-StringGrid1.GridLineWidth;
//StringGrid1.ColWidths[i]:=-1;
end else begin
StringGrid1.ColWidths[i]:=45;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := AppMessage;
end;
procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
if Msg.message = WM_KEYDOWN then begin
end;
end;
procedure TFormCollaboration.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
//StringGrid上で押された右矢印キーを無効化する
if Msg.message = WM_KEYDOWN then
begin
if ActiveControl is TStringGrid then
begin
if TStringGrid(ActiveControl).EditorMode then
begin
if Msg.wParam = VK_RIGHT then
begin
ShowMessage('捕まえた!');
Key:=#0;
end;
end;
end;
end;
end;
うわーん。Keyが「未定義の識別子」エラーに!!! よく見たら・・・
procedure TFormCollaboration.AppMessage(var Msg: TMsg; var Handled: Boolean);
procedure TFormCollaboration.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
//StringGrid上で押された右矢印キーを無効化する
if Msg.message = WM_KEYDOWN then
begin
if ActiveControl is TStringGrid then
begin
if TStringGrid(ActiveControl).EditorMode then
begin
if Msg.wParam=VK_RIGHT then
begin
//単に0を代入してwParamを書き換え
Msg.wParam := 0;
end;
end;
end;
end;
左矢印キーの押し下げにも、忘れずに対応☆
//StringGrid上で押された左矢印キーを無効化する
if Msg.message = WM_KEYDOWN then
begin
if ActiveControl is TStringGrid then
begin
if TStringGrid(ActiveControl).EditorMode then
begin
if Msg.wParam=VK_LEFT then
begin
//単に0を代入してwParamを書き換え
Msg.wParam := 0;
end;
end;
end;
end;
end;
翌日、左右の制御を合体させた方がイイと気づき、上の2つを合体させて・・・
procedure TFormCollaboration.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
//StringGrid上で押された左右の矢印キーを無効化する
if Msg.message = WM_KEYDOWN then
begin
if ActiveControl is TStringGrid then
begin
if TStringGrid(ActiveControl).EditorMode then
begin
if Msg.wParam=VK_RIGHT then
begin
//単に0を代入してwParamを書き換え
Msg.wParam:=0;
end;
if Msg.wParam=VK_LEFT then
begin
//単に0を代入してwParamを書き換え
Msg.wParam:=0;
end;
end;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
//Python39-32へのPath
AppDataDir:string;
begin
・・・
if DirectoryExists(AppDataDir) then
begin
//フォルダが存在したときの処理(コメント化)
//MessageDlg('Embeddable Pythonが利用可能です。',
// mtInformation, [mbOk] , 0);
PythonEngine1.AutoLoad:=True;
GitHubのPython4Delphiのダウンロードページには「The project is licensed under the MIT License.」とある。これは「改変・再配布・商用利用・有料販売すべてが自由かつ無料」であること、及び使用するにあたっての必須条件はPython4Delphiの「著作権を表示すること」と「MITライセンスの全文」or 「 MITライセンス全文へのLink」をソフトウェアに記載する、もしくは、別ファイルとして同梱しなさい・・・ということを意味する。
procedure TForm1.CMShowingChanged(var Msg: TMessage);
begin
inherited; {通常の CMShowingChagenedをまず実行}
if Visible then
begin
Update; {完全に描画}
//Formの表示終了時に以下を実行
Panel1.Height:=intPH;
intPH:=Panel1.Height;
intFH:=Form1.Height;
end;
end;
Formが生成される際に、Panel1とFormの高さをプログラムから指示して決定。
procedure TForm1.FormCreate(Sender: TObject);
begin
//Panel1とFormの高さを記憶する変数を初期化
intPH:=200;
intFH:=480;
end;
Formの大きさの変更イベントに合わせて、Panel1の高さを計算して決定。
procedure TForm1.FormResize(Sender: TObject);
begin
//比率を維持してPanel1の高さを変更
Panel1.Height:=Trunc(Form1.Height * intPH/intFH);
end;
procedure TForm1.CMShowingChanged(var Msg: TMessage);
begin
inherited; {通常の CMShowingChagenedをまず実行}
if Visible then
begin
Update; {完全に描画}
//Formの表示終了時に以下を実行
Memo1.Width:=intMW;
intMW:=Memo1.Width;
intFW:=Form1.Width;
end;
end;
Formが生成される際に、MemoとFormの大きさをプログラムから指示して決定。
procedure TForm1.FormCreate(Sender: TObject);
begin
//MemoとFormの幅を記憶する変数を初期化
intMW:=480;
intFW:=640;
end;
Formの大きさの変更イベントに合わせて、Memoの幅を計算して決定。
procedure TForm1.FormResize(Sender: TObject);
begin
//比率を維持してMemoの幅を変更
Memo1.Width:=Trunc(Form1.Width*intMW/intFW);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
//PythonのScriptを入れる
strScrList:TStringList;
//Pythonから送られたデータを保存する
strAnsList:TStringList;
begin
end;
最初に、Memo1を初期化し、データの入れ物をそれぞれ準備する。
begin
//初期化
Memo1.Clear;
//Scriptを入れるStringList
strScrList:=TStringList.Create;
//結果を保存するStringList
strAnsList:=TStringList.Create;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
//PythonのScriptを入れる
strScrList:TStringList;
//Pythonから送られたデータを保存する
//strAnsList:TStringList; //コメント化してしまう
begin
GitHubのPython4Delphiのダウンロードページには「The project is licensed under the MIT License.」とある。これは「改変・再配布・商用利用・有料販売すべてが自由かつ無料」であること、及び使用するにあたっての必須条件はPython4Delphiの「著作権を表示すること」と「MITライセンスの全文」or 「 MITライセンス全文へのLink」をソフトウェアに記載する、もしくは、別ファイルとして同梱しなさい・・・ということを意味する。
「python -m pip list」で「python.exe: No module named pip」が返る場合は、 pythonNN._pthファイルの修正(# import siteの前にある記号#(ナンバー)とその後ろの半角スペースを削除して import site だけにするコメント化の解除手続き)が正しく行われていない可能性が高い。 また、複数のライブラリのインストールを行うと、 pythonNN._pthファイル が修正前の状態に戻されてしまうこともあるようだ。要確認。
4.Numpyのインストール
続いて「愛しのNumpy」をインストール。
>python -m pip install numpy と入力してEnter!
「生きていてよかった」と思える至福の一瞬がここに。
警告:Consider adding this directory to PATH (このディレクトリをPATHに追加することを検討してください) は、まったく気にしない。Numpyが入ればいいのだ。わはは*(^_^)*♪
5.OpenCVのインストール
さらに、視力0.01かつ老眼&緑内障の恐れありと診断(2万ン千円も払ったのにイタいことばかり言いやがって:チ○ショー!「我が愛と哀しみの人間ドック2021年の記録」より抜粋)された私の眼に代わるSecret Weapon、目にも止まらぬ 走召 高速!でマークシートを読んでくれる機械の眼という意味がほぼない長い前置きを乗り越え、今、怒涛のクライマックス。「OpenCV」ライブラリがいよいよ My PC へ!