トップ回答者
Formをリロードさせたい

質問
回答
-
外池です。やっと私にもわかりました。「4行だけ書いてください」というのが、不適切な表現で誤解させてしまったようです。こちらでも同じ症状を再現することができました。
Module1のファイルの書き方がまずかったようです。Module Module1という最初の行と、End Moduleが必要でした。これ、最初から書かれていたと思うのですが、私の説明がマズくて、消してしまったんではないかと・・・。
Code SnippetModule Module1
Sub Main
Dim frm as Form1 'あるいはFormA
frm = New Form1 '次の改造で、
Application.Run(frm) 'この2行をループさせる。
End Sub
End Module
これで、やってみてください。
私も・・・、「宿題」やらないと。(滝汗)
-
外池です。よかったですー。
で、最初に、ここまで苦労しちゃったことを反省して、少し「お作法」的なことをまとめておきましょう。プログラムの本当にやりたいことの書き方とはあまり関係ないのですが、「このように書かないとダメ」というお約束みたいなものです。
-
変数、Sub、Functionは、かならず、Module ○○~End Moduleの間か、Class ○○~End Classの間に書くこと。これは、本当に「お約束」です。
-
Moduleの後ろの○○の部分は書き換えても良いですが、文は消してはいけません。
-
Classの○○の部分も変更しても良いのですが、特にFormの場合はFormのプロパティーを設定する画面でNameを変更すれば自動的に書き換えてくれるので、当面は自分で書き換えることは止めましょう。もちろん、文は消してはいけません。
で、「Close処理とできれば新しいゲームの生成処理」ですが、ヒントを書いておきますので、kassyiさんご自身でトライしてみてください。すべて、Module ○○~End Moduleの間と、Class ○○~End Classの間に、プログラムを書くことで実現できますので。
- FormAにもうひとつ、ゲームを続ける(新しいゲームを作るか)、止めるかを示すフラグになる変数(例えばNewGame)を加える。FormAの中のどこからでも呼び出せるように宣言する方法はわかりますよね? ただし、宣言文の頭に「Public」をつけてください。あと、宣言するところで、何か値を代入しちゃってください。こういう値のことを初期値とかデフォルト値とか呼びますが、「止める」を意味する値をデフォルト値にしておくと安全です。
- Publicをつけて宣言した変数は、Moduleのプログラムからも使うことができます。例えば、frm.NewGame(FormAが格納されている変数名frm、FormAの中での変数名NewGameをピリオドでつなぐ。)というようにすれば、読み出せるし、書き込めるし。(ちなみにPrivateをつけて宣言した変数は、このような操作はできなくなります。)
- FormAの右上の「×」のボタンを押すと閉じちゃいます。あと、FormAの中のプログラムでMe.Closeすると、やはり閉じちゃいます。そして、Moduleの中のプログラムのうち、Application.Run(frm)の次に実行が移るわけですが、今のままですとEnd Subなので、本当に全部終わりになります。ここで、frm.NewGameの値を調べてそのまま止めるか新しいゲームを作る操作に戻るか分岐する仕組みを書けば良いことになります。同じ処理を繰り返す(ループする)ためのDo~Loop という文を調べてください。
- FormAの側でNewGameの値をいじらなければ、Module側では「止める」操作しかできないわけですが、FormAの側で何か特別の操作をした場合にNewGameの値を変更しておけば、Module側で「新しいゲームを作る」処理もできるようになります。
プログラムで書けば、ほんの数行なのですが・・・、まぁ、イロイロ調べながら頑張ってみてください。
-
すべての返信
-
>1) まず、Visual Basicのバージョンを教えてください。VB6以前ですか? .Net以降ですか?
VBのバージョンは2008Expressです。
>2) リロードさせたい、ということは・・・、元のFormはどうしちゃっているのか、具体的な操作を教えてください。
まだVB初めて2週間もたっていない初心者なので、いらいら棒を手始めにつくっていています。
それに動く障害物をいれて、ゴールもしくはゲームオーバーしたら動く障害物を停止するようにしたら
障害物がはじめの位置からずれて動き出すようになってしまったからリロードさせようと思ったのです。
-
外池です。ここは・・・、かなり微妙な取り扱いが必要になりそうな雰囲気ですね・・・。
Dim frm as New FormA
frm.Show
を・・・、どこにお書きになってますか? もしかして、FormAのソースプログラムのどこかに書いておられませんか? 例えば、Loadイベントとか。これだと、なんと言いますか、FormAが次々に自身の分身を作り出して表示しようとしてしまいます。これは、StackOverFlowになる典型例と思われます。
どう、解決するか、ですが・・・、
その前に、ゲームの開始や終了を、どのようなイベントの処理(ボタンを押して、イベントを発生させているなど・・・、)をされているか説明して頂けると解決が早いかと思います。
-
外池です。少し補足(というか、推測ですが・・・)させてください。
kassyiさんのプログラムは、どうやって起動する設定になっていますか? おそらく・・・、FormAが直接起動するような設定になっているんじゃないかと思います。この場合は、二つの考え方でゲームを再スタートさせることが考えられます。
1) 今、見えているFormA自体は温存しておいて、動く部品の位置を最初の状態に戻すプログラムを頑張って書いて、再スタートさせる。(たぶん、いろんな部品の最初の位置は、デザイナ画面で部品ごとにプロパティーで設定されていると思うのですが、実は隠れた場所に、位置設定をするプログラムが書き込まれていますので、それをパクってくることができます。)
2) 今、見えているFormA自体は、捨てるて、別の新しいFormAを表示する。具体的には、「もう一度やる」のボタンを作っておいて、そのボタンが押されたときのイベントで、新しいFormAを作って表示させておいて、自分自身はCloseしてやる。
たぶん、2)が一番近道だとは思いますが・・・、普通のゲームっぽく見せようと思えば、1)にしたいですよね?
-
ほぼ、全体像わかりました。FormAとForm1は同じものだと理解しています。じゃぁ、FormAとしましょう。
まず、StackOverFlowになる原因ですが、FormAが起動します。起動したときに、自分自身の中のfrmに分身(用語で「インスタンス」と呼びます。)を作って入れようとします(自身の新しいインスタンスを作ってfrmに入れようとする)。で、分身の身になってみると(新しいインスタンスの身になってみると)、やはり、自身の中にfrmがあって、そこにさらに別のインスタンスを作って・・・、と、これが無限連鎖するわけで、作業用のメモリ(「スタック」と言います。メモリ全体から見ると、一部分なのですが)があふれてしまうわけです。
で、近道の2)でやってみるとして、
まず、Dim frm As New FormAは、今の場所からは削除してください。
で、「新しいゲーム」というようなボタンを作って、このボタンのイベントを処理するところに、Dim frm As New FormAと、frm.Showしてみてください。これで、新しいインスタンスが「初期状態」で表示されます。続けて、ゲームが終わった方の自分自身は、Me.Closeで閉じてやってください。
これで、プログラムの実行というか制御は新しいインスタンスへ移り、古いほうは消えてなくなります。
-
今外池さんの方法を試してみたら、新しいインスタンスが「初期状態」で表示されました。....最後の最後まで手をかけさせて申し訳ないのですが、もうひとつ教えてください。
Private Sub 新しいゲーム_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim frm As New Form1
frm.Show()
Me.Close()
End Subふつうプログラムは上から下へ実行されるのでこのようにしてみたのですがShowされないでCloseしてしまいました。
教えていただけるとうれしいです。
また新しくボタンを作ってそのボタンはMe.Close()を実行させることも試したのですが自分だけでなく新しく開いたほうまで閉じてしまいました。こっちのほうも教えていただけると幸いです。
-
ありゃ・・・、ダメでしたか。すいません、自分の環境でちょっとやってみます。
------
お恥ずかしい。
確かに、仰るとおりの動作になりました。
frmという変数が有効じゃなくなると、つまり、frmが有効なサブルーチンから出てしまうと、frmという変数が抹消されて、そこに代入されていた新しいFormAのインスタンスも、拠り所になる入れ物の変数を失って、抹消されてしまうわけですね。
ちょっと難しくなりますが、「正しい方法」でやってみますか・・・。かえってお手数おかけして申し訳ありませんが、以下の手順で作り変えて、元の動作をするかどうか、試してみてください。
1)プロジェクトに新しいファイル(モジュール)を追加する。
2)そのモジュールには、
Sub Main
Dim frm As New FormA
Application.Run(frm)
End Sub
と4行だけ書く。
3)My Projectの画面を開いて、アプリケーションの設定を変更するタブを開いて、
「アプリケーション フレームワークを有効にする」のチェックを外す。
スタートアップ・オブジェクトを「Sub Main」に変更する。
これで、一度走らせてください。意味は・・・、
プログラムの実行は、必ず、Sub Mainから始まるようになります。
Dim frm As New FormAで、ひとつ、FormAのインスタンスを変数frmに用意して、
Application.Run(frm)で、表示させているFormAに対する操作(ボタンを押すとか、マウスを移動させるとか)を受け付けてイベントを処理して、FormAが閉じられれば、
End Subでプログラムは終了です。
Dim frm As New FormA
Application.Run(frm)
をループさせるようにすれば、次々当たらしいゲームができるようになるのですが・・・。
-
いや、そこがですね、よくわからないんです。
------------
スタートアップオブジェクトに設定する画面は、先ほどのお話で、Sub Mainというのは見えていると思うのですが、これは、直接Module1のSub Mainを指しているのではないんです。プロジェクトのファイルのどこかにあるSub Mainを探し出して、そこから実行する、という意味です。
ところが、見つからない、というエラーが出る。しかも、スタートアップオブジェクトのリストに、Module1が現れていない様子。
そうすると、開発環境(プロジェクト)が、Module1が追加されていることに気づいていないのではないかと・・・。
------------
プロジェクトに関連付けるというのは、プロジェクト名、My Project、FormA、LoginForm(の名残)と、ツリー構造が表示されている「ソリューション・エクスプローラー」があると思うのですが、そこに、Module1がちゃんと入れておく、ということなんですが。
-
そのとおりです・・・。>スタートアップオブジェクトの設定の画面。
そっか・・・、「名前空間のステートメントが無効」が、まだ出たままなんですね・・・。
うーむ、これが出る理由がわからないなぁ。
ちょっと調べてみますから・・・、頭切り替えて・・・・、
とにかく、Sub Mainから入って、Formを表示させる方法でプログラムを書いてみる。
-
まったく新しいプロジェクトを作ってみてください。難しく考えずに・・・、
-
Windows アプリのプロジェクトを新しく作る。(すでに、空っぽのForm1はある)
-
このプロジェクトにModule1を追加して例の4行を書き加える。(FormAではなく、Form1にしてください)
-
My Projectの「アプリケーションフレームワークを有効にする」のチェックを外し、スタートアップオブジェクトをModule1にする。
-
走らせてみる。
って、やってみてもらえませんか? イライラ棒のプログラムは、一度保存しておきましょう・・・。
-
-
もし、まっさらなプロジェクトで上手くいくようだったら、もしかすると、あちこちに日本語の名前を使っているのがよくないのかも。
ファイル名や、プロジェクト名や・・・、基本的に、すべて、ローマ字半角で書くようにしてください。今、ルート名前空間のところに適当に日本語を入れてみたら、エラーになりました。
---- すいません、私事で恐縮ですが、帰宅の途につきますので・・・、夜中前までちょっとアクセスできません。
以下、ヒントをいくつか。
まずは、Sub MainからFormを開くやりかたをマスターする。
次に、FormにPublicなBoolean型変数(例えば、NewGame)を加える。Falseで初期化。
そうすると、Module1の中でも、frm.NewGameで内容が読み取れます。ということは・・・、
Code SnippetSub Main
'ここでは、Newを入れない、単に変数を宣言しておくだけ。インスタンスは作らない。
Dim frm As Form1
'なんらかのループを作る。
frm = New Form1
Application.Run(frm)
'ここでfrm.NewGameを調べて、Falseならそのまま終わり。Trueならループの最初に戻る。
End Sub
私の環境で、これで、上手く行ってるんですよ・・・。そちらも、上手くいくと良いのですが。
-
宿題しようと思ったらどーしてもやっぱり気になっていじってみました。一番最初の
Sub Mainのところを「ringo」に変えてみました。そうしたらスタトアップアプリの欄に
ringoは出ずにSub Mainのまんまでした。
それから例の4行ではなく
Sub Main
'ここでは、Newを入れない、単に変数を宣言しておくだけ。インスタンスは作らない。
Dim frm As Form1
'なんらかのループを作る。
frm = New Form1
Application.Run(frm)
'ここでfrm.NewGameを調べて、Falseならそのまま終わり。Trueならループの最初に戻る。
End Sub
この外池さんのコードを使ってまっさらなプロジェクトを作ってもやはり例の2つのエラーが出るだけでした。コピペしているのでタイプミスってことはありません。...今度こそ宿題に取り掛かりたいと思います。
-
外池です。やっと私にもわかりました。「4行だけ書いてください」というのが、不適切な表現で誤解させてしまったようです。こちらでも同じ症状を再現することができました。
Module1のファイルの書き方がまずかったようです。Module Module1という最初の行と、End Moduleが必要でした。これ、最初から書かれていたと思うのですが、私の説明がマズくて、消してしまったんではないかと・・・。
Code SnippetModule Module1
Sub Main
Dim frm as Form1 'あるいはFormA
frm = New Form1 '次の改造で、
Application.Run(frm) 'この2行をループさせる。
End Sub
End Module
これで、やってみてください。
私も・・・、「宿題」やらないと。(滝汗)
-
外池です。よかったですー。
で、最初に、ここまで苦労しちゃったことを反省して、少し「お作法」的なことをまとめておきましょう。プログラムの本当にやりたいことの書き方とはあまり関係ないのですが、「このように書かないとダメ」というお約束みたいなものです。
-
変数、Sub、Functionは、かならず、Module ○○~End Moduleの間か、Class ○○~End Classの間に書くこと。これは、本当に「お約束」です。
-
Moduleの後ろの○○の部分は書き換えても良いですが、文は消してはいけません。
-
Classの○○の部分も変更しても良いのですが、特にFormの場合はFormのプロパティーを設定する画面でNameを変更すれば自動的に書き換えてくれるので、当面は自分で書き換えることは止めましょう。もちろん、文は消してはいけません。
で、「Close処理とできれば新しいゲームの生成処理」ですが、ヒントを書いておきますので、kassyiさんご自身でトライしてみてください。すべて、Module ○○~End Moduleの間と、Class ○○~End Classの間に、プログラムを書くことで実現できますので。
- FormAにもうひとつ、ゲームを続ける(新しいゲームを作るか)、止めるかを示すフラグになる変数(例えばNewGame)を加える。FormAの中のどこからでも呼び出せるように宣言する方法はわかりますよね? ただし、宣言文の頭に「Public」をつけてください。あと、宣言するところで、何か値を代入しちゃってください。こういう値のことを初期値とかデフォルト値とか呼びますが、「止める」を意味する値をデフォルト値にしておくと安全です。
- Publicをつけて宣言した変数は、Moduleのプログラムからも使うことができます。例えば、frm.NewGame(FormAが格納されている変数名frm、FormAの中での変数名NewGameをピリオドでつなぐ。)というようにすれば、読み出せるし、書き込めるし。(ちなみにPrivateをつけて宣言した変数は、このような操作はできなくなります。)
- FormAの右上の「×」のボタンを押すと閉じちゃいます。あと、FormAの中のプログラムでMe.Closeすると、やはり閉じちゃいます。そして、Moduleの中のプログラムのうち、Application.Run(frm)の次に実行が移るわけですが、今のままですとEnd Subなので、本当に全部終わりになります。ここで、frm.NewGameの値を調べてそのまま止めるか新しいゲームを作る操作に戻るか分岐する仕組みを書けば良いことになります。同じ処理を繰り返す(ループする)ためのDo~Loop という文を調べてください。
- FormAの側でNewGameの値をいじらなければ、Module側では「止める」操作しかできないわけですが、FormAの側で何か特別の操作をした場合にNewGameの値を変更しておけば、Module側で「新しいゲームを作る」処理もできるようになります。
プログラムで書けば、ほんの数行なのですが・・・、まぁ、イロイロ調べながら頑張ってみてください。
-
-
kassyi さんからの引用 Code SnippetPrivate Sub 新しいゲーム_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim frm As New Form1
frm.Show()
Me.Close()
End Subふつうプログラムは上から下へ実行されるのでこのようにしてみたのですがShowされないでCloseしてしまいました。
教えていただけるとうれしいです。
また新しくボタンを作ってそのボタンはMe.Close()を実行させることも試したのですが自分だけでなく新しく開いたほうまで閉じてしまいました。こっちのほうも教えていただけると幸いです。
アプリケーションが終了してしまう直接の原因は,
プロジェクトのプロパティ(or My Project) の [アプリケーション] タブで,
アプリケーションフレームワークを有効にする(Enable application framework) が有効な時,
シャットダウンモード(Shutdown mode) が
スタートアップ フォームが閉じるとき (When startup fomr closes)
になっているためでしょう。それを
最後のフォームが閉じるとき (When last form closes)
にしておけば,閉じることはないと思います。