こんにちは。いつもお世話になってます。
Delphiでメニューバーを作っているのですが、
その中にテンプレートで元に戻す(Ctrl+Z)があると思うのですが、
これを実際に行うには、どうすればよいのですか?
VBだと、
SendKeys で簡単にできるのですが、Delphiではいったいどういう風にやればよいのでしょうか?
ご存知の方、宜しくお願いいたします。
TMemoやTRichEditのメソッドを呼び出してください。
たかみちえさん。はじめまして。
ありがとうございました。
教えていただいたことを、調べたんですが、よくわかりませんでした。
なので、今は、
procedure TForm1.Undo1Click(Sender: TObject);
begin
SendMessage(TextA.Handle , EM_UNDO , 0 , 0);
end;
という風にやってます。
これだと、TextAしか、できません。
これを、今アクティブなEDITにするには、どうすればいいのですか?
宜しくお願いします。
アクティブウィンドウをクラス参照変数に入れておいて、
その変数.Undo でどうでしょう?
---------------------------------------------------------------------
var ActiveEdit: TCustomEdit; // TEdit,TRichEdit両方を参照できるようにするため
procedure TForm1.EditEnter(Sender: TObject);
begin
ActiveEdit := TCustomEdit(Sender);
// ActiveEdit変数参照先を、Sender(イベントを発生させたオブジェクト)に
end;
procedure TForm1.Undo1Click(Sender: TObject);
begin
ActiveEdit.Undo; // ActiveEdit変数の参照先にUndo
end;
---------------------------------------------------------------------
VCLリファレンスの『TEdit』あたり参照。
追記します、
ちなみに、過去ログにある理由によって、
SelTextプロパティで設定して挿入したテキストをアンドゥさせることはできません。
たかみちえさん。ありがとうございました。
教えていただいたとおり、やったらうまくいきました。
これは、全てのEnterイベントに書かないといけないのですか?
たぶん、いろんなフォームで使うので、できれば、共通で使えるようにしたいのですが、どうすればよいのですか?
宜しくお願いいたします。
それぞれのフォームで、
begin
Edit1.OnEnter := Form1.EditEnter;
Edit2.OnEnter := Form1.EditEnter;
...
とすればOKです。
EditEnterを用意するFormオブジェクトは最後に破棄するようにしてください。
# そうでない場合、最後に破棄するオブジェクトに変更しましょう
そうしないと、万が一先に破棄されてしまってOnEnterが発生したとき、アクセス違反が発生すると思います。
OnEnterイベントは、オブジェクトインスペクタの"イベント"タブで設定できます。
たいして面倒なことでもないと思うので、それでいいでしょう。
相当に多いのならば、設計時にOnEnterイベントを設定したTMemoをコピーして
いくつもペーストすればいいです。
ActiveEdit変数にオブジェクトを入れる処理をいろいろなフォームに書くのが面倒ならば、
Unitを作って関数にしてみてはどうでしょう?
implement
procedure SetActive(Object:TObject);
var ActiveEdit:TCustomEdit;
interface
procedure SetActive(Object:TObject);
begin
ActiveEdit := TCustomEdit(Sender);
end;
ユニットを参照設定に加えることをお忘れなく
にしのさ〜ん。\(^o^)/
いつもありがとうございます。
>それぞれのフォームで、
>begin
> Edit1.OnEnter := Form1.EditEnter;
> Edit2.OnEnter := Form1.EditEnter;
> ...
>とすればOKです。
これは、どこのイベントで行うのですか?
>EditEnterを用意するFormオブジェクトは最後に破棄するようにしてください。
これは、Close時かDestory時に行うんですよね。
いつも、迷惑ばかりかけて申し訳ありませんが、
もう少し、詳しく教えていただけますでしょうか?
宜しくお願いします。m(_ _)m
たかみちえさん。ありがとうございます。
>Unitを作って関数にしてみてはどうでしょう?
できれば、そうしたいと思っています。
質問なんですけど
implementは、implementationとは、違うのでしょうか?
それと、
>procedure SetActive(Object:TObject);
でエラーがでてしまいます。
何かUsesしないといけないのでしょうか?
何かものすごく初歩的なことを聞いて申し訳ないんですが、
宜しくお願いいたします。
> これは、どこのイベントで行うのですか?
失礼、書くのを忘れていました。
OnCreateイベントです。
> これは、Close時かDestory時に行うんですよね。
自身で作成したフォームでなければ、プロジェクトソース内で作成され、破棄されます。
もし、自身で作成したフォームであれば、最後に閉じるフォームにEditEnterを用意すればOKです。
> implementは、implementation
間違いですね。僕も前にやりました^^;
implementationが正しいです。
ユニットを作成して、implementationより前に関数定義を書き、implementationの後ろに関数の全体を書きます。
Form1のusesにかかれている項目をコピーしておくとよいでしょう。
形としては、
unit ユニット名;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;{ Form1からコピーする }
procedure SetActive(Value: TCustomEdit);
implementation
var
ActiveEdit:TCustomEdit;
procedure SetActive(Value: TCustomEdit);
begin
ActiveEdit := Value;
end;
end.
こんな形です。
細かいエラーはできるだけ調べてみてください。ケアレスミスは誰に出もありますし、聞くよりヘルプをみた方が早いですから。
ありがとうございます、にしのさん。
書き間違えと書き損じがありました。
ふつうにツールバーからユニットを作れば、それらは大体ついてくるので問題なしです。
> 何かUsesしないといけないのでしょうか?
中で使用している変数や定数、クラスを宣言しているユニットものが必要です。
(にしのさんのでももちろんいいですけど、今回の場合、WindowsとかはUsesしなくてもいいですね^^;)
そのクラスがどこで定義されているかは、そのクラスの名前にキャレットをのせてF1で、大体わかりますから。
(DelphianWorldやいろんなホームページで見つけたコンポーネントやクラスは、ダウンロードしたユニットそのものが必要)
そのほか、WM_??などのウィンドウメッセージ定数はMessages
多くのAPI(一部別のユニットで定義されている場合もあり)は、Windows
のユニットに宣言されています。
アプリケーションレベルの変数などの解説は、だいたいヘルプに載っているので、
F1で調べて、Usesに加えれば大丈夫です。
途中から失礼します。
ActiveControl プロパティで,フォーム上でフォーカスがある
コントロールを取得できます。
procedure TForm1.Undo1Click(Sender: TObject);
begin
(ActiveControl as TCustomEdit).Undo;
end;
でいいのでは。
>(ActiveControl as TCustomEdit).Undo;
これだとフォーカスがある場合のみ有効なので、違うコントロールにフォーカスがある場合は動作しないですよ。
いや、必ずフォーカスがあたっていれば問題ないですが(^^;
こんにちは。
>これだとフォーカスがある場合のみ有効なので、違うコントロールにフォーカスがある場合は動作しないですよ。
えっと、質問者さんは、
>これを、今アクティブなEDITにするには、どうすればいいのですか?
と言われているので、いいのではないじょうか。
それと補足ですが、前のコードはエディット系以外のコントロールが
アクティブだとエラーがでるので、下記のコードの方がいいですね。
procedure TForm1.Undo1Click(Sender: TObject);
begin
if ActiveControl is TCustomEdit then
TCustomEdit(ActiveControl).Undo;
end;
の方がいいですね。
こんにちは。
いろいろとありがとうございました。
皆さまに教えていただいたのを参考にUNITを作りました。
unit UnitM;
interface
uses
StdCtrls;
// 元に戻す(Ctrl+Z)
procedure MUndo(ActiveEdit: TCustomEdit);
// コピー(Ctrl+C)
procedure MCopy(ActiveEdit: TCustomEdit);
// 貼り付け(Ctrl+V)
procedure MPaste(ActiveEdit: TCustomEdit);
// 切り取り(Ctrl+X)
procedure MCut(ActiveEdit: TCustomEdit);
implementation
procedure MUndo(ActiveEdit: TCustomEdit);
begin
try
ActiveEdit.Undo;
except
ActiveEdit.free;
end;
end;
procedure MCopy(ActiveEdit: TCustomEdit);
begin
try
ActiveEdit.CopyToClipboard;
except
ActiveEdit.free;
end;
end;
procedure MPaste(ActiveEdit: TCustomEdit);
begin
try
ActiveEdit.PasteFromClipboard;
except
ActiveEdit.free;
end;
end;
procedure MCut(ActiveEdit: TCustomEdit);
begin
try
ActiveEdit.CutToClipboard;
except
ActiveEdit.free;
end;
end;
end.
呼び出す側
procedure TForm1.Undo1Click(Sender: TObject);
begin
if ActiveControl is TCustomEdit then
MPaste(TCustomEdit(ActiveControl));
end;
これで、うまく行くようになりました。
どうも、ありがとうございました。
あと、ひとつなんですけど。。。
UNDOだけ、うまくいきませんでした。
EDITに連続して文字を貼り付けてUNDOすると、一番最初に戻ってしまいます。
例
1)EDIT1にAAAAと貼り付ける。(EDITの文字AAAA)
これでUNDOだと、元に戻ります。(EDITの文字 )
例
1)EDIT1にAAAAと貼り付ける。(EDITの文字AAAA)
2)EDIT1にAAAAと貼り付ける。(EDITの文字AAAAAAAA)
これでUNDOだと(EDITの文字 )こういう風に最初に戻ってしまします。
これを、直前のものだけUNDOにするには、どうすればよいのですか?
しつこいようですが、宜しくお願いいたします。m(_ _)m
>EDITに連続して文字を貼り付けてUNDOすると、一番最初に戻ってしまいます。
TMemo(Windowsの標準エディットボックス)の仕様です。
NotePadを見てみればわかると思いますけど、瞬間的に何度も入力しても、一回の入力とみなしてしまいます。
回避したいのなら、アンドゥバッファを自分で管理しないといけません。
DelphianWorldのエディタコンポーネントなどを使ったほうが早いと思いますけど。
ところで、
begin
try
ActiveEdit.CutToClipboard;
except
ActiveEdit.free;
end;
end;
ですけど、どうもおかしいというか…
except節ですけど、この場合引数がすでにTCustomEditで定義されているので、
不要です。ないに越したことはないですけど。
(メモリ関連とかでエラーが起こったとき対策?)
簡単にやるのなら、OnEnterでActiveEdit変数に入れる直前に、
SenderがTCustomEdit以下のクラスかどうか確かめたほうがいいと思います。
(Edit以外のOnEnterに、ActiveEdit変数に入れる処理を加えないのなら、それすらなくっても平気だと思いますけど)
とりけしとりけし
> 簡単にやるのなら、OnEnterでActiveEdit変数に入れる直前に、
> SenderがTCustomEdit以下のクラスかどうか確かめたほうがいいと思います。
ActiveControlを使うんですよね、何言ってんでしょわたし・・・(^^ゞ
ええ、じゃあ、
try exceptを使うより、
とりあえずMPasteなどにはTObjectでわたして、
as演算子で試したあとキャストして使うといいと思います。
それと
> ActiveEdit.free;
ですけど、ActiveEditはクラス参照変数なので、Freeすることはすなわち、アクティブなコントロール(=エディットコントロール)を削除してしまうと思うのですけど。
ところで、この方法だと、
エディットコントロール>ボタン>メニュー項目
の順でクリックすると、動作しません。
質問のとおりだとそれでいいとは思いますけど、それでもいいでしょうか?
わたしは最初、
"直前にアクティブだったエディット(=編集中のエディット)コントロール"を操作するんだと思ったんですけど…。
まあ、ソフトの仕様にもよりますけど、そっちのほうが使う人にとって便利じゃないかなと思ったので…。
それと、もし上のように"フォーカスがあるときのみ"という動作でやるのなら、
フォーカスがほかのコントロールにあるときは、
メニューを使用不可にするとかしたほうが、親切だと思いますけど、どうでしょうか?
(メニューが表示される寸前に、ActiveControlをチェックする)
マキさん wrote:
>Delphiでメニューバーを作っているのですが、
>その中にテンプレートで元に戻す(Ctrl+Z)があると思うのですが、
>これを実際に行うには、どうすればよいのですか?
>これを、今アクティブなEDITにするには、どうすればいいのですか?
ということなら、繰り返しになりますが、
procedure TForm1.Undo1Click(Sender: TObject);
begin
if ActiveControl is TCustomEdit then
TCustomEdit(ActiveControl).Undo;
end;
で十分だと思います。
メニューバーなら、フォーカスは移動しません。
ボタンなら、TSpeedButton にしておけば、フォーカスは移動しません。
その上で、エディット以外にフォーカスを持つコントロールがあるの
なら、その時は、メニューを使用不可にするのが親切なUIですね。
さらには、取り消しバッファが空のときも使用不可にするべきですね。
Delphi6 以降なら、TActionList 標準アクションを使えば、
これらのことは自動でやってくれます。
あけましておめでとうございます。
本年も宜しくお願いいたします。
いろいろとご教授いただきまして本当にありがとうございました。
いろいろと試した結果、TActionList で作成することにしました。
いろいろと、教えていただいて、TActionList かよ。と
突っ込みたくなると思いますが、こんな簡単に作れるとは、
思ってませんでした。
ほんとに、ご迷惑をおかけして申し訳ありませんでした。
いろいろと教えていただいた皆様、ほんとに感謝しております。
ありがとうございました。
ツイート | ![]() |