- PR -

MDI親フォームのToolBarを切り替えるには?

投稿者投稿内容
あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2005-10-20 12:05
C#.NETアプリケーションで、MDIインターフェイスのシステムを作成しています。

アクティブなMDIの子フォームに合わせて、親フォームのMainmenuとToolBarを
切り替えているのですが、ToolBarの切り替えで問題が発生します。

(1) 子フォームにあらかじめ持たせておいたToolBarオブジェクトに切り替える。
具体的には、Controls.Remove()とControls.Add()を使っています。
(2) 子フォームにはSystem.Windows.Forms.ToolBarButton[]を持たせておき、
toolBar.Buttons.Clear()と、toolBar.Buttons.AddRange()を使って
置き換える。
(3) 親フォームにToolBarを子フォームの数分持たせておき、Show()、Hide()を
切り替える。

という、3つの方法で試して見ましたが、どの場合も同じ現象が発生します。

※ちなみに子フォームはclosingでイベントをキャンセルし、Hide()しています。
 今回は仕様上、フォームを閉じてしまうことはできないためです。
※ツールバーの各ボタンは子フォームを開くボタンです。

現象というのは、

(A) 閉じたはずのフォームが他のフォームを開くときに現れる。
調査した結果、ToolBarのオブジェクトに変更を加えると全てのHide()して
いるフォームにShowのイベントが飛んできます。
(B) Aの現象のあと、子フォームを移動できなくなる、サイズ調整できなくなる、
最大化しても親フレームの中で最大になるだけで親フレームとドッキング
しない、などの現象が発生する。
(C) 上記とは関係ないかも知れませんが、最大化して親フレームとドッキングした
ときに表示される最小化、最大化、クローズボタンが、一瞬、たくさん見える。

というものです。

簡単なテストモジュールを作って調査していますので、システムの他の機能が
障害になっていることは考えられないかと思います。

根本的にToolBarを切り替える方法が間違っていて、もっと他に正しい方法がある
のではないかと思い、探しております。

どなたかご存知の方は居られませんでしょうか?

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

まどか
ぬし
会議室デビュー日: 2005/09/06
投稿数: 372
お住まい・勤務地: ますのすし管区
投稿日時: 2005-10-20 17:29
引用:

アクティブなMDIの子フォームに合わせて、親フォームのMainmenuとToolBarを
切り替えているのですが、
※ツールバーの各ボタンは子フォームを開くボタンです。


この二つから実際のやりたいことがイメージできません。。。

それはおいといて、

引用:

根本的にToolBarを切り替える方法が間違っていて、もっと他に正しい方法がある
のではないかと思い、探しております。


まずオブジェクト(ToolBar)の所有を移すのはやらないほうがいいと思います。
今回のは、閉じられた範囲でVisibleを切り替えるようなこととは違うと思います。

まずは親子それぞれの役目をはっきり分けて明確にしたほうが良いでしょう。
例えば、子フォームの基本クラスを作成して各子フォームはそれを継承します。
基本クラスへToolBarを作成するための情報を公開するプロパティなどを実装します。
親はアクティブフォームから基本クラスのそのプロパティから情報取得して自身のToolBarを書き換える。
こうすれば、子はToolBarを作るための情報を保持すればよいだけになり
親はToolBarのイベントに専念できると思います。
ToolBarを「切り替える」のではなく「再構築」ですね。

引用:

(A) 閉じたはずのフォームが他のフォームを開くときに現れる。
調査した結果、ToolBarのオブジェクトに変更を加えると全てのHide()して
いるフォームにShowのイベントが飛んできます。


結果的にVisible=Trueになるようなコードが動作しているのでは。
あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2005-10-20 18:15
引用:

まどかさんの書き込み (2005-10-20 17:29) より:
引用:

アクティブなMDIの子フォームに合わせて、親フォームのMainmenuとToolBarを
切り替えているのですが、
※ツールバーの各ボタンは子フォームを開くボタンです。


この二つから実際のやりたいことがイメージできません。。。


例えば、「A」というツールバーボタンを押せば、Aに対応した子フォームがActivate
されます。

引用:

引用:

根本的にToolBarを切り替える方法が間違っていて、もっと他に正しい方法がある
のではないかと思い、探しております。


まずオブジェクト(ToolBar)の所有を移すのはやらないほうがいいと思います。
今回のは、閉じられた範囲でVisibleを切り替えるようなこととは違うと思います。

まずは親子それぞれの役目をはっきり分けて明確にしたほうが良いでしょう。
例えば、子フォームの基本クラスを作成して各子フォームはそれを継承します。
基本クラスへToolBarを作成するための情報を公開するプロパティなどを実装します。
親はアクティブフォームから基本クラスのそのプロパティから情報取得して自身のToolBarを書き換える。
こうすれば、子はToolBarを作るための情報を保持すればよいだけになり
親はToolBarのイベントに専念できると思います。
ToolBarを「切り替える」のではなく「再構築」ですね。


これは、上記の
引用:

(2) 子フォームにはSystem.Windows.Forms.ToolBarButton[]を持たせておき、
toolBar.Buttons.Clear()と、toolBar.Buttons.AddRange()を使って
置き換える。


にあたるのではないでしょうか?

引用:

引用:

(A) 閉じたはずのフォームが他のフォームを開くときに現れる。
調査した結果、ToolBarのオブジェクトに変更を加えると全てのHide()して
いるフォームにShowのイベントが飛んできます。


結果的にVisible=Trueになるようなコードが動作しているのでは。


そうです。
ToolBarに何らかの変更を加えた時点でVisible=Trueになるようです。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2005-10-20 18:59
ちょっと興味があったので、MdiChildActivate イベントで同じようなことをしたのですが、
提示された現象を再現することができませんでした。

とりあえず、必要な部分のみのソースを提示して頂けると助かります。(*_ _)

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2005-10-21 09:41
じゃんぬねっとさん、どうもです。

いろいろと変更したので分からなくなってしまいましたが、
最初のテストプログラムは以下のような感じです。

引用:

public class FormABC : System.Windows.Forms.Form
{
private System.Windows.Forms.ToolBar toolBar1;
private System.Windows.Forms.MainMenu Mainmenue;

public FormA childFormA;
public FormB childFormB;
public FormC childFormC;

public FormABC()
{
InitializeComponent();

childFormC = new FormC();
childFormC.MdiParent = this;
childFormC.Show();

childFormB = new FormB();
childFormB.MdiParent = this;
childFormB.Show();

childFormA = new FormA();
childFormA.MdiParent = this;
childFormA.Show();
}
}

public class FormA : System.Windows.Forms.Form
{
private System.Windows.Forms.ToolBar toolBar1;
private System.Windows.Forms.MainMenu Mainmenue;

private void FormA_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
this.Hide();
}

private void FormA_Activated(object sender, System.EventArgs e)
{
this.MdiParent.Menu = this.Mainmenue;
this.MdiParent.Controls.RemoveAt(0);
this.MdiParent.Controls.Add(this.toolBar1);
}

private void toolBar1_ButtonClick(object sender,
System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
FormABC parent = (FormABC)this.MdiParent;

switch (toolBar1.Buttons.IndexOf(e.Button))
{
case 0:
parent.childFormA.Show();
parent.childFormA.Activate();
break;
case 1:
parent.childFormB.Show();
parent.childFormB.Activate();
break;
case 2:
parent.childFormC.Show();
parent.childFormC.Activate();
break;
default:
break;
}
}
}



FormABCがMDI親フォームで、一応、デフォルトのメニューとツールバーを
持っています。

FormA、FormB、FormCはMDI子フォームで、内容は同じです。
テストのためリファクタリングしてません。

上記コードの、
引用:

private void FormA_Activated(object sender, System.EventArgs e)
{
this.MdiParent.Menu = this.Mainmenue;
this.MdiParent.Controls.RemoveAt(0);
this.MdiParent.Controls.Add(this.toolBar1);
}



のthis.MdiParent.Controlsを操作したところで、Visible=Trueになる
イベントが全てのMDI子フォームに送られてしまうようです。

Visibleの値を保持しておいて復帰したりも試しましたが、
その後の動作が不安定になりました。
(具体的には最初の投稿のとおりです)

MDIでToolBarを切り替えるのって一般的なことだと思うのですが、
どなたか問題なくできている方はいらっしゃらないでしょうか。

じゃんぬねっとさん、まどかさん、よろしくです。

[ メッセージ編集済み 編集者: あぶぽん 編集日時 2005-10-21 09:43 ]
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2005-10-21 10:02
引用:

あぶぽんさんの書き込み (2005-10-21 09:41) より:

MDIでToolBarを切り替えるのって一般的なことだと思うのですが、
どなたか問題なくできている方はいらっしゃらないでしょうか。


そういうアプリケーションは、「切り替え」というより、
もともとすべてのアイテムを持っていて、可視・不可視を切り替えているだけです。
丸ごと取得して変更しているわけではないです。(ちらついちゃいますから)

# これから検証に入ります。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2005-10-21 10:29
引用:

あぶぽんさんの書き込み (2005-10-21 09:41) より:

コード:

private void FormA_Activated(object sender, System.EventArgs e)
{
    this.MdiParent.Menu = this.Mainmenue;
    this.MdiParent.Controls.RemoveAt(0);
    this.MdiParent.Controls.Add(this.toolBar1);
}




これ、非常にまずいですね。
0 が ToolBar である保証はありません。

適当に以下のようにやりましたが、予想通りちらつきはするものの再現はしませんでした。
本来はこのように親からやるべきです。

コード:

private FormA formChild1 = null;
private FormB formChild2 = null;
private FormC formChild3 = null;

private void button1_Click(object sender, System.EventArgs e) {
    this.IsMdiContainer = true;

    formChild1 = new FormA();
    formChild1.MdiParent = this;
    formChild1.Show();

    formChild2 = new FormB();
    formChild2.MdiParent = this;
    formChild2.Show();

    formChild3 = new FormC();
    formChild3.MdiParent = this;
    formChild3.Show();
}

private void Form1_MdiChildActivate(object sender, EventArgs e) {
    if (this.ActiveMdiChild == this.formChild1) {
        FormA hFormChild = (FormA)this.ActiveMdiChild;
        ToolBarButton[] toolBarButtons = new ToolBarButton[hFormChild.myToolBar.Buttons.Count];

        for (int i = 0; i <= hFormChild.myToolBar.Buttons.Count - 1; i++) {
            toolBarButtons[i] = hFormChild.myToolBar.Buttons[i];
        }

        this.toolBar1.Buttons.Clear();
        this.toolBar1.Buttons.AddRange(toolBarButtons);
    } else if (this.ActiveMdiChild == this.formChild2) {
        FormB hFormChild = (FormB)this.ActiveMdiChild;
        ToolBarButton[] toolBarButtons = new ToolBarButton[hFormChild.myToolBar.Buttons.Count];

        for (int i = 0; i <= hFormChild.myToolBar.Buttons.Count - 1; i++) {
            toolBarButtons[i] = hFormChild.myToolBar.Buttons[i];
        }

        this.toolBar1.Buttons.Clear();
        this.toolBar1.Buttons.AddRange(toolBarButtons);
    } else if (this.ActiveMdiChild == this.formChild3) {
        FormC hFormChild = (FormC)this.ActiveMdiChild;
        ToolBarButton[] toolBarButtons = new ToolBarButton[hFormChild.myToolBar.Buttons.Count];

        for (int i = 0; i <= hFormChild.myToolBar.Buttons.Count - 1; i++) {
            toolBarButtons[i] = hFormChild.myToolBar.Buttons[i];
        }

        this.toolBar1.Buttons.Clear();
        this.toolBar1.Buttons.AddRange(toolBarButtons);
    }
}


やっぱり、各フォームに何を表示するのかの情報だけ持たせて、
Visible で可視・不可視を切り替える方が、手軽さ・保守性・ちらつかない、
どれを取っても良いコトづくめだと思うんですが、如何でしょうか?

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2005-10-21 10:58
じゃんぬねっとさん、

この現象のミソは、子フォームをCloseせずに、

引用:

(省略)
this.Closing += new System.ComponentModel.CancelEventHandler(this.FormA_Closing);
}

private void FormA_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
this.Hide();
}


としているところです。

引用:

やっぱり、各フォームに何を表示するのかの情報だけ持たせて、
Visible で可視・不可視を切り替える方が、手軽さ・保守性・ちらつかない、
どれを取っても良いコトづくめだと思うんですが、如何でしょうか?


これというのは、私はずっと気付かなかったのですが、
もしかして、ToolBarButtonのVisibleのことですか?

ToolBarのVisibleに関しては冒頭にも書いたように試してますし、
MdiParent.ControlsをClearしても、Addしても、この現象(
子フォームのVisibleがTrueになってしまう)が発生するので。。。

スキルアップ/キャリアアップ(JOB@IT)