トップ回答者
MDIフォームの作成が、わかりません。

質問
-
初心者の問題ですみません。。。。。
お手数を、おかけします。。。。
Windows フォームアプリ
.NET Windowsフォーム(WinForms)アプリを作成するためのプロジェクトテンプレート”.NET5で作りました。。。。
Microsoft Visual Studio Community 2019
Version 16.9.3で、
Microsoft.NET Framework
Version 4.8.04084の環境でしております。
Visual C# 2019 逆引き大全 500の極意の、問題で、
P215Tips117で、MDIフォームを作成すると題し、
アプリケーションウィンドウの中で、複数のウィンドウ
をひらくためには、MDI(Multiple Document Interface)
を使用します。
フォームを、MDI親フォーム(アプリケーションウィン
ドウ)として、ウィンドウの中にMDI子フォーム(子ウイン
ドウを表示するには、まずMDI親フォームと
なる、フォームのIsMdiContainerプロパティーを、
「true」にします。
次に、フォームに、MenuStripコントロールを配置し、
メニューを作成します。
(ここで、ファイルのメニューに、ドロップダウンで、
新規が出るようにします。)
(ここからができません@@;)
??(新規をクリックすると、子フォームが、表示されるよ
うに、します。)??
フォーム内に、MDI子フォーム(フォーム)を表示する
には、表示するフォームのMdiParentプロパティに
親フォームのインスタンスを指定します。
??(インスタンスの指定の仕方もわかりません)??
子フォームには、リッチテキストボックスを、
画面全体に配置し、サイズや、タイトルバーを
指定して開きます。
この(新規をクリックすると、子フォームが、
表示されるようにます。)から、どうすれば
良いのか、わかりません**;
フォームの
コードは以下の通りです。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ui117
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void 新規ToolStripMenuItem_Click(object sender, EventArgs e)
{
Form myFm = new Form(); //子フォームの作成
//リッチテキストボックスの作成と設定
RichTextBox myRT = new RichTextBox();
myRT.Dock = DockStyle.Fill;
//子フォームの設定
myFm.MdiParent = this; //親フォームを設定
myFm.Text = "文書" + MdiChildren.Length; //タイトルバーの設定
myFm.Size = new Size(200 , 200); //フォームのサイズを設定
myFm.Controls.Add(myRT); //リッチテキストボックスの追加
myFm.Show(); //フォームを開く
}
}
}
回答
-
参考にされているという 逆引き大全を持っていないため、書籍を読まないと分からない点については答えられませんが、分かる範囲で回答してみます。
.NET Windowsフォーム(WinForms)アプリを作成するためのプロジェクトテンプレート”.NET5で作りました。。。。
以下、私見ではありますが…。
現段階で .NET 5 を選択することは、あまりお奨めしません(WinForm の場合は特に)。経験者であれば良いのですが、初心者レベルであるのなら、.NET Framework 4.8 を利用した方が無難です。
理由は幾つかありますが…大きい所は下記の2点。
- .NET 5 は2020年11月にリリースされたばかりですが、あと 1年足らず(来年2月)にはサポート期限を迎えてしまいます(ちなみに .NET Core 3.1 は来年12月までのサポートです)。また、破壊的仕様変更も多いです。
- 約 20 年の歴史を持つ .NET Framework 版の WinForm デザイナに比べ、.NET Core 版の WinForm デザイナは 1 年前に登場したばかりです。そのためか、機能的にはまだ不十分なところもあり、必ずしも初心者向けとは言い難いです。(たとえば MenuStrip の設定作業も、.NET Framework 版の方がやりやすいです)
——とまぁ、それらは本題では無いので横に置いといて…と。
ひとまずは .NET 5 前提のままで回答します。
次に、フォームに、MenuStripコントロールを配置し、メニューを作成します。
まず、Form1 に MenuStrip のメニューを作成するところまでは出来ていますね?
(正確に言うと、MenuStrip はコントロールではなくコンポーネントです)作成したらプロパティ一覧で、上部のドロップダウン(Form1 などが表示される部分)から、自分で作成した [新規]メニューの項目(ToolStripMenuItem) を探してください。
新規メニューそれを選択したら、⚡アイコンを選択してイベント一覧に切り替えて、[Click]と書かれている項目をダブルクリックします。
そうすると、「private void 何某_Click(object sender, EventArgs e)」と書かれたコードが生成されると共に、Click イベントとの関連付けが自動的に行われます。先ほどのイベント一覧に戻ってみると、Click イベントの項目に、このイベントハンドラの割り当てが記載されていることが分かるかと思います。
このイベント割り当てが行われていないと、クリックしても処理が呼び出されません。
イベント割り当てが行われいることを確認出来たら、その中に、先に提示されていた
Form myFm = new Form(); //子フォームの作成
(中略)
myFm.Show(); //フォームを開く
までのコードを、その中に書いてください。これで実行すれば、[新規]メニューをクリックするたびに、子画面が表示されるようになるはずです。
あと、リッチテキストボックスを、どのようにして、入れ込んで、関連付ければいいのか、わかりやすく、
入れ込んで関連付ける…というのは、どのような作業を指していますか?
どのような機能を設けたいのか、具体的に書いていただければ、手順を伝えられるかもしれません。参考にされている書籍がどういう流れになっているのか分かりませんが、通常はリッチテキストボックスの配置なども、デザイナで行った方が簡単なので、そちらの方法を書いてみます。
ソリューション エクスプローラーでプロジェクトを右クリックし、[追加]-[フォーム (Windows フォーム)]で、新しいフォーム Form2.cs を追加してください。
Form2 のデザイナが起動したら、Form2 のプロパティ一覧の Size 欄に、「200, 200」と入力してください。
サイズを指定出来たら、ツールボックスから RichTextBox を Form2 に貼ります。そして貼り付けた RichTextBox のプロパティ一覧にある Dock プロパティから、[Fill]な項目を選択します。
これで準備完了です。
Form1 のコード編集画面に戻って、先ほどの [新規] メニューの Click イベントの箇所を開き、処理を下記の 4 行だけにします。
var child = new Form2(); child.MdiParent = this; child.Text = "文書" + MdiChildren.Length; child.Show();
これで、デザインしておいた Form2 の内容が MDI 子フォームとして開くようになります。プログラムで RichTextBox を貼っていくよりも、直感的に設計できるのではないでしょうか。
- 編集済み 魔界の仮面弁士MVP 2021年4月2日 10:02
- 回答としてマーク taket 2021年4月2日 14:07
すべての返信
-
??(新規をクリックすると、子フォームが、表示されるように、します。)??
現時点で、void 新規ToolStripMenuItem_Click は呼び出されていますか?
呼び出されていない場合は、[新規] の Click イベントへの割り当てが漏れているので、デザイナーのプロパティウィンドウから、イベント⚡タブを開いて、割り当てを確認してみてください。
Form myFm = new Form(); //子フォームの作成
このコードは、コントロール等が何も貼られていない、空の子フォームを作成するためのコードです。
(作成するだけです。その後で Show を呼び出すまでは表示されません)ここでは「new Form()」としていますが、通常は「new Form2()」などとして、あらかじめコントロールを配置しておいた自作フォームを new でインスタンス化してセットするのが一般的だったりします。
今回は、あらかじめデザインしておいた自作フォームを使うのではなく、空のフォームに対して、「myFm.Controls.Add(myRT);」として、RichTextBox を実行時に割り当てているようですね。
どちらの方法でも良いですが、この後、リッチテキストに入力された値を読み取ったり、テキストを設定したりするためのコードを用意するのであれば、個人的にはフォームデザイナーでレイアウト済みの子フォームを準備しておいた方がお手軽だと思います。
フォーム内に、MDI子フォーム(フォーム)を表示するには、表示するフォームのMdiParentプロパティに親フォームのインスタンスを指定します。
これは、「myFm.MdiParent = this; //親フォームを設定」と書かれているコードにあたります。
子フォームには、リッチテキストボックスを、画面全体に配置し、サイズや、タイトルバーを指定して開きます。
今回のコードでは、Click イベント内でリッチテキストボックスの設置やタイトルバーの指定を行っていますね。
リッチテキストボックスの配置や Size 指定はデザイン時に済ませておくこともできますが、タイトルバーに表示する
「myFm.Text = "文書" + MdiChildren.Length; //タイトルバーの設定」
の箇所だけは変動値なので、少なくともここは残して Click 時に動的に指定する必要があります。 -
参考にされているという 逆引き大全を持っていないため、書籍を読まないと分からない点については答えられませんが、分かる範囲で回答してみます。
.NET Windowsフォーム(WinForms)アプリを作成するためのプロジェクトテンプレート”.NET5で作りました。。。。
以下、私見ではありますが…。
現段階で .NET 5 を選択することは、あまりお奨めしません(WinForm の場合は特に)。経験者であれば良いのですが、初心者レベルであるのなら、.NET Framework 4.8 を利用した方が無難です。
理由は幾つかありますが…大きい所は下記の2点。
- .NET 5 は2020年11月にリリースされたばかりですが、あと 1年足らず(来年2月)にはサポート期限を迎えてしまいます(ちなみに .NET Core 3.1 は来年12月までのサポートです)。また、破壊的仕様変更も多いです。
- 約 20 年の歴史を持つ .NET Framework 版の WinForm デザイナに比べ、.NET Core 版の WinForm デザイナは 1 年前に登場したばかりです。そのためか、機能的にはまだ不十分なところもあり、必ずしも初心者向けとは言い難いです。(たとえば MenuStrip の設定作業も、.NET Framework 版の方がやりやすいです)
——とまぁ、それらは本題では無いので横に置いといて…と。
ひとまずは .NET 5 前提のままで回答します。
次に、フォームに、MenuStripコントロールを配置し、メニューを作成します。
まず、Form1 に MenuStrip のメニューを作成するところまでは出来ていますね?
(正確に言うと、MenuStrip はコントロールではなくコンポーネントです)作成したらプロパティ一覧で、上部のドロップダウン(Form1 などが表示される部分)から、自分で作成した [新規]メニューの項目(ToolStripMenuItem) を探してください。
新規メニューそれを選択したら、⚡アイコンを選択してイベント一覧に切り替えて、[Click]と書かれている項目をダブルクリックします。
そうすると、「private void 何某_Click(object sender, EventArgs e)」と書かれたコードが生成されると共に、Click イベントとの関連付けが自動的に行われます。先ほどのイベント一覧に戻ってみると、Click イベントの項目に、このイベントハンドラの割り当てが記載されていることが分かるかと思います。
このイベント割り当てが行われていないと、クリックしても処理が呼び出されません。
イベント割り当てが行われいることを確認出来たら、その中に、先に提示されていた
Form myFm = new Form(); //子フォームの作成
(中略)
myFm.Show(); //フォームを開く
までのコードを、その中に書いてください。これで実行すれば、[新規]メニューをクリックするたびに、子画面が表示されるようになるはずです。
あと、リッチテキストボックスを、どのようにして、入れ込んで、関連付ければいいのか、わかりやすく、
入れ込んで関連付ける…というのは、どのような作業を指していますか?
どのような機能を設けたいのか、具体的に書いていただければ、手順を伝えられるかもしれません。参考にされている書籍がどういう流れになっているのか分かりませんが、通常はリッチテキストボックスの配置なども、デザイナで行った方が簡単なので、そちらの方法を書いてみます。
ソリューション エクスプローラーでプロジェクトを右クリックし、[追加]-[フォーム (Windows フォーム)]で、新しいフォーム Form2.cs を追加してください。
Form2 のデザイナが起動したら、Form2 のプロパティ一覧の Size 欄に、「200, 200」と入力してください。
サイズを指定出来たら、ツールボックスから RichTextBox を Form2 に貼ります。そして貼り付けた RichTextBox のプロパティ一覧にある Dock プロパティから、[Fill]な項目を選択します。
これで準備完了です。
Form1 のコード編集画面に戻って、先ほどの [新規] メニューの Click イベントの箇所を開き、処理を下記の 4 行だけにします。
var child = new Form2(); child.MdiParent = this; child.Text = "文書" + MdiChildren.Length; child.Show();
これで、デザインしておいた Form2 の内容が MDI 子フォームとして開くようになります。プログラムで RichTextBox を貼っていくよりも、直感的に設計できるのではないでしょうか。
- 編集済み 魔界の仮面弁士MVP 2021年4月2日 10:02
- 回答としてマーク taket 2021年4月2日 14:07
-
横で見ている訳ではないのですから、どこまでできているのか、何が起きているのかをきちんと説明してください。
エラーが出るのか、何も起きないのか。イベントは呼び出されているのか否か、あるいは呼ばれているかどうかを判断する方法が分からないのか、などなど。
- 編集済み 魔界の仮面弁士MVP 2021年4月2日 12:22
-
//コードはこういう状態です**:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinFormsApp24
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
}
private void 新規ToolStripMenuItem_Click(object sender, EventArgs e)
{
// Form myFm = new Form(); //子フォームの作成
////リッチテキストボックスの作成と設定
//RichTextBox myRT = new RichTextBox();
//myRT.Dock = DockStyle.Fill;
////子フォームの設定
//myFm.MdiParent = this; //親フォームを設定
//myFm.Text = "文書" + MdiChildren.Length; //タイトルバーの設定
//myFm.Size = new Size(200, 200); //フォームのサイズを設定
//myFm.Controls.Add(myRT); //リッチテキストボックスの追加
//myFm.Show(); //フォームを開く
}
private void 新規toolStripMenuItem1_Click(object sender, EventArgs e)
{
//Form myFm = new Form(); //子フォームの作成
////リッチテキストボックスの作成と設定
//RichTextBox myRT = new RichTextBox();
//myRT.Dock = DockStyle.Fill;
////子フォームの設定
//myFm.MdiParent = this; //親フォームを設定
//myFm.Text = "文書" + MdiChildren.Length; //タイトルバーの設定
//myFm.Size = new Size(200, 200); //フォームのサイズを設定
//myFm.Controls.Add(myRT); //リッチテキストボックスの追加
//myFm.Show(); //フォームを開く
var child = new Form2();
child.MdiParent = this;
child.Text = "文書" + MdiChildren.Length;
child.Show();
}
}
} -
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
private void 新規ToolStripMenuItem_Click(object sender, EventArgs e)
private void 新規toolStripMenuItem1_Click(object sender, EventArgs e)
似たような名前のメソッドが 3 つありますね。
これ、どうやって作りましたか?
private void …と手で入力したりはしていませんか?また、先の手順で述べた下記の箇所ですが…
新規メニューそれを選択したら、⚡アイコンを選択してイベント一覧に切り替えて、[Click]と書かれている項目をダブルクリックします。
この操作によって生成されたコードは、上記 3 つのうちどれですか?
これはつまり、先程確認手順として述べた先ほどのイベント一覧に戻ってみると、Click イベントの項目に、このイベントハンドラの割り当てが記載されていることが分かるかと思います。
このイベント割り当てが行われていないと、クリックしても処理が呼び出されません。
の項目欄に表示されている名前がどれであるのか、という事です。
最初の回答で『現時点で、void 新規ToolStripMenuItem_Click は呼び出されていますか?』とも聞いていたはずですが、この逆質問に答えて頂けていません。
先程の『イベントは呼び出されているのか否か、あるいは呼ばれているかどうかを判断する方法が分からないのか』と書いたのも、この重要な割り当てが行われているかどうかを確認したかったからです。
- 編集済み 魔界の仮面弁士MVP 2021年4月2日 13:33
-
最初の
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
menuStrip1を、クリックしているとできました。。。
次の
private void 新規ToolStripMenuItem_Click(object sender, EventArgs e)
は、サンプルファイルのコードをコピーしました。
最後の、
private void 新規toolStripMenuItem1_Click(object sender, EventArgs e)
は、雷マークをクリックして作りました。
消すと、エラーが出るので、容易に消せなくて。。。 -
MenuStrip のデザインとかイベント割り当てとかを考えると、.NET 5 で作るよりも、.NET Framework の方のプロジェクト テンプレートで作った方が、断然楽ですよ…?
消すと、エラーが出るので、容易に消せなくて。。。
C# の場合はコードから勝手に消したら駄目なんです。(C# ではなく Visual Basic であれば、コード エディタ上から直接消しちゃっても問題ないのですけれどね)
C# の場合は、プロパティ ウィンドウに表示されるイベント一覧を開いて、そこの Click 欄に記述されている「menuStrip1_ItemClicked」を解除する作業が必要です。
イベント割り当ての解除を行わずに消してしまうとエラーになります。名前の変更時にも注意しましょう。
慣れてくれば、デザイナーコードを直接修正することでもできますが…それは初心者にはハードルが高いですよね。
サンプルファイルのコードをコピーしました。
それが間違っています。
イベント処理で呼ばれるコードは、コードエディタにただ書くだけは駄目なのです。何度か指摘しているように、プロパティ ウィンドウの ⚡ タブに表示されるイベントに対して割り当てないといけません。
そもそも menuStrip1_ItemClicked がそうであったように、イベントに割り当てようとした時点で、自動的にコードの枠組みが生成されるので、自分でイベントハンドラを作る必要は無いです。
で。
たとえ menuStrip1_ItemClicked が呼び出されたとしても、手順としてはまだ間違っています。
それはあくまで、「MenuStrip」のイベントだからです。
今回必要なのは、「ToolStripMenuItem」のイベントです。[ファイル]-[新規]の項目をどうやって作ったのか説明されていませんが、おそらく [新規] は ToolStripMenuItem になっているはずです。
参考にされた書籍にもある通り、ToolStripMenuItem の Click イベントであれば、
(object sender, EventArgs e) という引数定義のはずですが、MenuStrip では
(object sender, ToolStripItemClickedEventArgs e) ですよね? 別物なんです。MenuStrip は、メニュー全体を指し示すコンテナなので、[ファイル]-[新規] という階層があったとしても、[新規] に辿り着く前に、menuStrip1_ItemClicked の処理が反応してしまいます。
.NET Framework 版の WinForm デザイナであれば、デザイン時に MenuStrip の階層をドロップダウンで辿れるので、[ファイル]-[新規] メニューを直接ダブルクリックするだけで、Click イベントハンドラーを生成してもらえるのですが…。
.NET 5 版の WinForm デザイナは、現状そこまで洗練されておらず、デザイン時にメニュー階層を直接辿ることができません。なので先に説明した通り、フォーム上の要素をダブルクリックするのではなく、プロパティ ウィンドウから
自分で作成した [新規]メニューの項目(ToolStripMenuItem) を探してください。
新規メニューそれを選択したら、⚡アイコンを選択してイベント一覧に切り替えて、[Click]と書かれている項目をダブルクリックします。という手順を踏む必要があります。
-
イベントは呼び出されているのか否か、あるいは呼ばれているかどうかを判断する方法が分からないのか。。
ですが、どちらもわかりません**;コードウィンドウを開くと、一番左端に余白がありますよね。
そこをクリックしてみてください。下記のように ●印が付きます。
この状態で実行すると、マークした箇所を通過する前に、そこで一時停止するようになります。この一時停止させるためのマークを「ブレーク ポイント」と呼びます。
もう一度クリックするとブレーク ポイントは解除されます。
また、[F9]キーを押すことでも、現在行にブレーク ポイントを張ったり、あるいは解除したりすることができます。一時停止させた後は、[F10]キーを押すか、ツールバーのステップオーバーを押すと、一行ずつ処理が進みます。
この機能を使うと、処理がどのように進んでいるのかを容易に追跡できるでしょう。(この一行ずつ進めていく動作のことを、ステップ実行と呼びます)
また、一行ずつ実行させるのではなく、通常通り続けて実行させたい場合には、[F5] キーを押すか、ツールバーの [▶続行] を押して再開させてください。
- 編集済み 魔界の仮面弁士MVP 2021年4月2日 14:41
-
新規toolStripMenuItem1_Click
新規toolStripMenuItem_Click実際のところ、コードウィンドウに記載される名前は、なんでも良いのです。
引数などの定義さえ間違っていなければ、好きな名前を付けられます。もちろん分かりやすい名前を付けることも大切ですが、
もっとも重要なのは ⚡ のイベントに割り当てられているかどうか、という点です。- 編集済み 魔界の仮面弁士MVP 2021年4月2日 14:39