NSTextFieldをプログラムで作成したときの挙動について

428 views
Skip to first unread message

hiro

unread,
Feb 16, 2009, 4:39:22 AM2/16/09
to cocoa-dev-japan
皆様。またまたお助けください。

訳あって、IBを使わずにCocoaアプリケーションを作成しています。
テキストフィールドをWindowに張りつけ、文字入力やキーボードのリターンイベント
を取りたいのですが、とれなくて困っています。

具体的には次のようにコーディングしました。

---------------------------------------------------------------------------------
NSTextField* textField = [[NSTextField alloc] initWithFrame:NSMakeRect
(200,200, 100,20)];
[textField setSelectable:YES];
[textField setEditable:YES];
[textField setSelectable:YES];
[textField setTarget:self];
[textField setAction:@selector(processAction:)];

[[window contentView] addSubview:textField];
---------------------------------------------------------------------------------
(windowはNSWindowです)

別のアプリをIBで作成し、NSTextFieldを配置して実行すると、問題なく文字入力もイベントも取得できます。そこで、IB上で
NSTextFieldの設定をいじって、Editableのチェックを外すと入力できなくなったので、setEditableメソッドの問題だと思っ
て上記のようなコードにしたのですが、文字入力もイベントも取得できません。

何かほかにやらなければならない設定や、メソッド呼び出しがあるのでしょうか?

よろしくお願いいたします。

hiro

unread,
Feb 16, 2009, 8:11:54 PM2/16/09
to cocoa-dev-japan
自己レスです

> ---------------------------------------------------------------------------------
> NSTextField* textField = [[NSTextField alloc] initWithFrame:NSMakeRect
> (200,200, 100,20)];
> [textField setSelectable:YES];
> [textField setEditable:YES];
> [textField setSelectable:YES];
> [textField setTarget:self];
> [textField setAction:@selector(processAction:)];
>
> [[window contentView] addSubview:textField];
> ---------------------------------------------------------------------------------
> (windowはNSWindowです)
>

このコードですが,IBを全く使わずにやっております.
できない原因を確かめるため,IBを使ってボタンを1つだけ配置し,
ボタンのクリックイベントでNSTextFieldを貼付けるようにしたところ,うまく動作しました.

したがって,問題はNSTextFieldの生成や貼り付け方ではなく,メイン関数なのではないかという気がしています.

メイン関数のコードは次のようになります.

----------------------------------------------------------------
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

id controller = [[MainController alloc] init];
id app = [NSApplication sharedApplication];

[app setDelegate:controller];

[app run];

[pool drain];

return 0;

----------------------------------------------------------------

MainControllerの中で,NSWindowの生成や,NSTextFieldの貼付け処理をおこなっています.

NSApplicationMainの中でやっている処理で,上記以外処理があると考えているのですが,参考になるドキュメントやコードを
ご存知の方いらっしゃらないでしょうか?

以上,よろしくお願いいたします.

wang

unread,
Feb 17, 2009, 4:10:09 AM2/17/09
to cocoa-dev-japan
まったく想像で書いているのですが、この手のコードはmain関数ではなく
アプリケーションのデリゲートのapplicationDidFinishLaunching:のなかでやるのが常識になっています。
これはNSApplicationの初期化処理が未了の場合に使えるべき機能が使えなかったりすることが
あるためです。コードをそちらに移してお試しください。

hiro

unread,
Feb 18, 2009, 7:34:10 AM2/18/09
to cocoa-dev-japan
wang様

お返事ありがとうございます.

こちらですが,解決いたしました.

正確には,「できない」ということが分かりました.

Cocoaアプリケーションの場合,main.mには

return NSApplicationMain(argc, argv);

とだけ書かれていますが,この代わりに

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
id app = [NSApplication sharedApplication];
[app run];
[pool drain];
return 0;

このようにしても,NSApplicationMainと完全に同じではないようです.

したがって,XIBファイルを全く使わずにCocoaアプリケーションを作ることは困難だと思います.

同じく機能させるためには,一般には公開されていないAPIを使えばできるかもしれませんが,
それらは使うべきではないようです(バージョンアップ時に変更になる可能性がある).

wang

unread,
Feb 18, 2009, 11:40:59 AM2/18/09
to cocoa-dev-japan
xibを使わないって、ほんとうにひとつも使わないっていう意味だったんですね。
そのWindowのnibファイルを作らないという意味かと思っていました。

メニューの初期化とかの処理もあると思いますが、それも全部MainControllerの中で書いていたんですか?

そこまでしてCocoaを使いたい理由がわかりませんが、アプリケーション部分はCarbonで実装して
そこからCocoaのWindowなどを作って呼び出す方法もとれますので、まずCarbonのnibなしのアプリケーション実装方法を調べてみてはど
うでしょうか?

hirai hiroaki

unread,
Feb 18, 2009, 11:57:06 AM2/18/09
to cocoa-d...@googlegroups.com

On 2009/02/18, at 21:34, hiro wrote:

>
> wang様
>
> お返事ありがとうございます.
>
> こちらですが,解決いたしました.
>
> 正確には,「できない」ということが分かりました.

荻原剛志さん著書
Objective-C MacOS X プログラミング
14章:例題簡易画像ビューア

この章には、あえてInterface Builderを利用しないサンプル
コードを書いてあります

hiro

unread,
Feb 18, 2009, 9:30:46 PM2/18/09
to cocoa-dev-japan
wang様

お返事ありがとうございます.

On 2月19日, 午前1:40, wang <kuroki_masay...@hotmail.com> wrote:
> xibを使わないって、ほんとうにひとつも使わないっていう意味だったんですね。
> そのWindowのnibファイルを作らないという意味かと思っていました。

はい.全く使わないという意味でした.誤解させてしまってすみません.

> メニューの初期化とかの処理もあると思いますが、それも全部MainControllerの中で書いていたんですか?

main.mにはNSApplicationの初期化と,runループの開始だけを記述し,DelegateのMainControllerでウィンド
ウの
生成やNSTextFieldの生成,はりつけなどを行っていました.
テストプログラムとしてやってみたので,メニューは作成していませんでした.

> そこまでしてCocoaを使いたい理由がわかりませんが、アプリケーション部分はCarbonで実装して
> そこからCocoaのWindowなどを作って呼び出す方法もとれますので、まずCarbonのnibなしのアプリケーション実装方法を調べてみてはど
> うでしょうか?

当初,アプリケーション開始時にウィンドウを出すのではなく,外部のイベントを拾ってウィンドウを表示したいと
いう要求がありました.ところが,IBの使い方やXIBファイルにもなれていないCocoa初心者なので,とにかく
コマンドラインアプリケーションを作り,そこでウィンドウを生成すればよいと安易に考えたわけです.
それと同時に,これをいい機会に,IBやXIBファイルの内部で何が行われているのか調べようと思い,やってみたというわけです.

現在は,File's OwnerとFirst ResponderだけのXIBを使い,目的は達成できました.
Carbonを使ったやり方までご紹介いただき,ありがとうございました(当然Carbonも初心者なので,これから調べてみます).

hiro

unread,
Feb 18, 2009, 9:35:43 PM2/18/09
to cocoa-dev-japan
hirai様

お返事ありがとうございます.

> > 正確には,「できない」ということが分かりました.
>
> 荻原剛志さん著書
> Objective-C MacOS X プログラミング
> 14章:例題簡易画像ビューア
>
> この章には、あえてInterface Builderを利用しないサンプル
> コードを書いてあります

はい.この簡易画像ビューアのコードを参考に作成しました.
このアプリケーションではNSTextFieldは使ってなかったと思いますが,実際にやってみたらできなかった訳です.
このやり方でも,ボタンのイベントはとれるのですが,キーボードの入力がとれないみたいです.

wang

unread,
Feb 19, 2009, 1:16:56 AM2/19/09
to cocoa-dev-japan
Windowを起動時に表示しないのはIBでNSWindowのbehavior>Visible at Launchのチェックをはずすだけで実現で
きます。

目的に応じて標準的な作り方をしたほうが手間がかからないのでベターだと思います。

narumi

unread,
Feb 19, 2009, 5:12:36 AM2/19/09
to cocoa-dev-japan
ターゲットアクションというやりかたに固執されるんであれば実現方法はわかりませんが
やりたいこと自体はNotificationとNSTextFieldのDelegateMethodでできそうですが、そちらは試してみました?

narumi

unread,
Feb 19, 2009, 6:57:36 PM2/19/09
to cocoa-dev-japan
独り言っぽいのが何度も続いて申し訳ないですが、
単にウインドウがキーウインドウになってなくてキーボードイベントちゃんと拾えてないだけじゃないかって気がしてます。

提示されてるコードはなんら変な部分はみつけられないのですが
ウインドウの初期化をどうやってるのかがわからないと、もう憶測の域をでることができない
肝心なところが示されていないように思います。

hiro

unread,
Feb 19, 2009, 8:42:09 PM2/19/09
to cocoa-dev-japan
wang様


On 2月19日, 午後3:16, wang <kuroki_masay...@hotmail.com> wrote:
> Windowを起動時に表示しないのはIBでNSWindowのbehavior>Visible at Launchのチェックをはずすだけで実現で
> きます。

なるほど,この方法は存じませんでした.これからこの方法でやりたいと思います.

> 目的に応じて標準的な作り方をしたほうが手間がかからないのでベターだと思います。

おっしゃる通りです.これから経験を積みたいと思います.

ありがとうございました.

大坂博幸

unread,
Feb 20, 2009, 2:26:14 AM2/20/09
to cocoa-d...@googlegroups.com
hirochanosakaといいます。私もキーウィンドウになっていないのかと思って荻原氏の著書に書いてあるソースコードを拾って調べてみましたが、ウィンドウオープン直後からキーイベントを拾えますよ。
WinCtrl.mの画像を表示するNSImageViewの部分をコメントアウトしてhiroさんのソースを貼付けただけですが、

- (void)windowSetUp {

・・・一部引用のため途中は省略

 vwrect.origin = NSZeroPoint;

/*

    imageview = [[NSImageView alloc] initWithFrame:vwrect];

    [imageview setImage:docImage];

    [imageview setEditable:NO];

    [imageview setImageScaling:YES];

    [imageview setFrameSize: winrect.size];

    [window setContentView:imageview];

    [imageview release];

*/

NSTextField* textField = [[NSTextField alloc] initWithFrame:NSMakeRect(200,200, 100,20)];

[textField setSelectable:YES];

[textField setEditable:YES];

[textField setTarget:self];

[textField setAction:@selector(processAction:)];

[[window contentView] addSubview:textField];

[textField release];

}
setSelectableは二ついらないと思うので、カットしましたが、原因は別のところではないでしょうか?
NSWindowの生成方法を荻原氏の著書の該当部分から変更しましたか?

hiro

unread,
Feb 20, 2009, 5:22:33 AM2/20/09
to cocoa-dev-japan
大坂様

お返事ありがとうございます.

On 2月20日, 午後4:26, 大坂博幸 <hirochanos...@gmail.com> wrote:
> hirochanosakaといいます。私もキーウィンドウになっていないのかと思って荻原氏の著書に書いてあるソースコードを拾って調べてみましたが、ウィンドウオープン直後からキーイベントを拾えますよ。

なぬ.本当ですか.ということは,ウィンドウの生成に問題があるということですね.

確かに,荻原さんのソースをそのまま使った訳ではありません.全ソースを書かせていただくと,

main.m
----------------------------------------------------------------
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

id controller = [[MainController alloc] init];
id app = [NSApplication sharedApplication];

[app setDelegate:controller];

[app run];

[pool drain];

return 0;

----------------------------------------------------------------

<MainController.m>
----------------------------------------------------------------
- (void) applicationDidFinishLaunching:(NSNotification*) aNotification
{

NSRect windowRect = NSMakeRect(200.0, 200.0, 800.0, 600.0);
window = [[NSWindow alloc] initWithContentRect:windowRect
styleMask: (NSResizableWindowMask | NSClosableWindowMask |
NSTitledWindowMask)
backing: NSBackingStoreBuffered
defer: NO];

NSTextField* urlField = [[NSTextField alloc] initWithFrame:NSMakeRect
(200, 200, 100, 20)];
[urlField setEditable:YES];
[urlField setSelectable:YES];

[[window contentView] addSubview:urlField];

[window makeKeyAndOrderFront:self];

}
----------------------------------------------------------------

です.ご指摘のように,キーウィンドウに設定できていないと思うのですが,何をすればキーウィンドウに
設定できるのか分かりませんでした..

XIBファイルを使った場合だと,上のコードでキー入力のイベントを取得できましたので,問題はmain関数の部分だと
考えていました...大変申し訳ありません -> 皆様

windowSetUpの中を見ても,キーウィンドウに設定するようなメソッドを実行しているようには見えないのですが,
どのメソッド呼び出しがキーウィンドウに設定しているのでしょうか?

narumi

unread,
Feb 22, 2009, 5:15:01 AM2/22/09
to cocoa-dev-japan
このコードでも今回問題としてる部分に関しては、ターゲットとアクションを付加するだけで動きますね。
Command-Qが効かないし、メニューはないしで不便でしたが。

残るはコンパイル方法やバンドルの構成とかかなぁ、何か問題があるとしたら。
もうレスポンダーチェーンをチェックしながら自分でデバッグしてもらうしかないかと。

Yanagisawa

unread,
Feb 22, 2009, 8:12:01 PM2/22/09
to cocoa-d...@googlegroups.com
On Feb 18, 2009, at 4:34 AM, hiro wrote:

> 正確には,「できない」ということが分かりました.

自分も興味があったので少し試してみましたが... もしかし
て普通に実行ファイルだけを作っていませんか?
ただの実行ファイルだけだと正しく GUI アプリとして認識さ
れないようです。認識されないとシステムが正しく初期化を行って
くれないようです。

以下、この前提でもう少し詳細を書きますが、

> 同じく機能させるためには,一般には公開されていないAPI
> を使えばできるかもしれませんが,
> それらは使うべきではないようです(バージョンアップ時に
> 変更になる可能性がある).

自分が理解した範囲では +[NSApplication sharedApplication]
中で主要な初期化がほぼ全て行われるようです。ただ、この時点で
特定の条件を満たしていないと GUI アプリとして必要な初期
化(ドックの表示、メニューの登録、イベント分配の初期化等)が
行われないようです。
逆にここで正しく初期化されれば、後は -[NSApplication run]
でいいようです。

その「特定の条件」が明確に分かったわけではないのですが、試し
てみたところ、少なくとも以下のどちらかの場合は、そこそこ動く
ようになる模様:

- パッケージ形式で実行ファイルが置かれている、すなわち
AppName.app/Contents/MacOS/AppName のような構造になっている
(荻原氏のサンプルコードもこれ)

- 実行ファイルのリソースフォークに plst リソースを付ける
(旧Mac OSのリソースフォークを持ったバイナリの形式。現
在は非推奨な形式だと思われる)


まあ普通は Xcode/IB/nib/パッケージ形式 でアプリを
作れば十分でしょうが、たまにはこの手のことを機会にウインドウ
システムの詳細を掘ってみるのも悪くない...かも?

Yanagisawa

hiro

unread,
Feb 22, 2009, 10:41:18 PM2/22/09
to cocoa-dev-japan
narumi様

お返事ありがとうございます。

On 2月22日, 午後7:15, narumi <j.nar...@gmail.com> wrote:
> このコードでも今回問題としてる部分に関しては、ターゲットとアクションを付加するだけで動きますね。
> Command-Qが効かないし、メニューはないしで不便でしたが。

むむ、動きましたか?

> 残るはコンパイル方法やバンドルの構成とかかなぁ、何か問題があるとしたら。

私、上記のコードをXcode3.1を使って、Command Line Utility -> Foundation Toolをひな形として作成し
ました。

ここが問題でしょうか?

narumi様は具体的にどのような手順でプロジェクトを作成されたのか、参考までに教えていただけないでしょうか?

よろしくお願いいたします。

hiro

unread,
Feb 22, 2009, 10:46:44 PM2/22/09
to cocoa-dev-japan
Yanagisawa様

お返事ありがとうございます。

On 2月23日, 午前10:12, Yanagisawa <yanag...@gmail.com> wrote:
> On Feb 18, 2009, at 4:34 AM, hiro wrote:
>
> > 正確には,「できない」ということが分かりました.
>
> 自分も興味があったので少し試してみましたが... もしかし
> て普通に実行ファイルだけを作っていませんか?

私は、Xcode3.1を使って、Command Line Utility -> Foundation Toolをひな形として作成しました。

そして、実行もXcodeから行いました。

> ただの実行ファイルだけだと正しく GUI アプリとして認識さ
> れないようです。認識されないとシステムが正しく初期化を行って
> くれないようです。

なるほど。おそらくこの辺りが原因のような気がします。

> 以下、この前提でもう少し詳細を書きますが、
>
> > 同じく機能させるためには,一般には公開されていないAPI
> > を使えばできるかもしれませんが,
> > それらは使うべきではないようです(バージョンアップ時に
> > 変更になる可能性がある).
>
> 自分が理解した範囲では +[NSApplication sharedApplication]
> 中で主要な初期化がほぼ全て行われるようです。ただ、この時点で
> 特定の条件を満たしていないと GUI アプリとして必要な初期
> 化(ドックの表示、メニューの登録、イベント分配の初期化等)が
> 行われないようです。
> 逆にここで正しく初期化されれば、後は -[NSApplication run]
> でいいようです。
>
> その「特定の条件」が明確に分かったわけではないのですが、試し
> てみたところ、少なくとも以下のどちらかの場合は、そこそこ動く
> ようになる模様:
>
> - パッケージ形式で実行ファイルが置かれている、すなわち
> AppName.app/Contents/MacOS/AppName のような構造になっている
> (荻原氏のサンプルコードもこれ)
>
> - 実行ファイルのリソースフォークに plst リソースを付ける
> (旧Mac OSのリソースフォークを持ったバイナリの形式。現
> 在は非推奨な形式だと思われる)

なるほど。この辺がかなり怪しいですね。

> まあ普通は Xcode/IB/nib/パッケージ形式 でアプリを
> 作れば十分でしょうが、たまにはこの手のことを機会にウインドウ
> システムの詳細を掘ってみるのも悪くない...かも?

そうですね。せっかくなので調べてみたいと思います。

貴重な情報、ありがとうございました。
Reply all
Reply to author
Forward
0 new messages