C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[7]: クラシック表示でのボタン上のイメージ表示について


(過去ログ 110 を表示中)

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■65123 / inTopicNo.1)  クラシック表示でのボタン上のイメージ表示について
  
□投稿者/ キム (1回)-(2013/02/06(Wed) 21:18:18)

分類:[C#] 

2013/02/07(Thu) 09:12:27 編集(投稿者)

VS2008 C#(.NET Framework3.5)を使用しています。
OSはWindows XP及びWindows 7です。
クラシック表示でのボタン上のイメージの挙動に関する質問です。

クラシック表示にした場合、ボタンを押すと斜め右下に引っ込むみます。
この際、ボタンテキストも数ピクセル右下にずれて表示されます。
ところが、ボタンのImageプロパティで設定した画像はボタンを押しても右下にずれてくれません。
テキストとイメージを表示している場合テキストだけが動くので、とても違和感があります。
イメージもテキストと同様に動くようにするにはどうすればいいのかご教示いただけると幸いです。

試したこと
・ImageListプロパティでも試しましたが結果は同じでした。
・TextImageRelationによって挙動が変わるか試しましたが結果は同じでした。

現在検討している方法
プロパティ等で一発で解決する方法は見つけられませんでした。
そこで、ImageListに通常イメージと右下にずらしたイメージを登録して、ボタンの状態により切り替える(ImageIndexを変更する)方法を検討しています。
・右下にずらしたイメージは通常イメージからコードで生成します。
・クラシック表示時のみ切り替えを行います。
・クラシック表示時かどうかはVisualStyleRenderer.IsSupportedで判定します。
・ボタンが押されている状態かどうかは知る方法がなかったので、KeyのUp/Down及びマウスのUp/Downイベントで判定します。
・マウスが押されたままマウスカーソルがボタン外に移動した場合のためにMoveイベントでも判定を行います。
・判定結果によりImageIndexを変更します。

ボタンの現在の状態判定が煩雑であり、キーとマウスを同時に押した場合の挙動にも不安があります。
もう少し直接的でシンプルな方法あればとても助かります。
または、ボタンの現在の状態をもっと簡単に知る方法があれば現在検討している方法でも解決できそうです。

以上、よろしくお願いします。
引用返信 編集キー/
■65124 / inTopicNo.2)  Re[1]: クラシック表示でのボタン上のイメージ表示について
□投稿者/ キム (2回)-(2013/02/06(Wed) 21:30:26)
すみません、プロジェクトの種類を書き忘れました。
Windows フォーム アプリケーションです。
また、ボタンは、System.Windows.Forms.Buttonです。

よろしくお願いします。
引用返信 編集キー/
■65129 / inTopicNo.3)  Re[2]: クラシック表示でのボタン上のイメージ表示について
□投稿者/ shu (169回)-(2013/02/07(Thu) 09:30:47)
No65124 (キム さん) に返信

オーナードローでは駄目ですか?
引用返信 編集キー/
■65135 / inTopicNo.4)  Re[3]: クラシック表示でのボタン上のイメージ表示について
□投稿者/ ?L?&#128; (1回)-(2013/02/07(Thu) 14:48:54)
No65129 (shu さん) に返信

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

オーナードロー試してみました。
派生クラスでButtonRenderer.DrawButtonを使えばボタンの描画は出来ますし、イメージの描画位置も指定できました。
ただ、ボタンの状態(押されているのかどうか)を直接知る方法がない点に変わりはないので、やはり自前で判定しなければなりません。
しかし、判定と描画を自前ですることになるので、そこに食い違いが発生することがなくなるのは良いと思いました。

逆に、標準のボタンと完全に同じ挙動とするのは困難と感じました。
例えばVisualStyle有効時の描画で、フォーカスを得たときに標準のボタンだとフォーカスを示す破線枠の外側に水色の枠が出ますが、
ButtonRenderer.DrawButtonによる描画だとフォーカスを示す破線枠が描画されるだけでの外側に水色の枠が出なかったりします。

用途を限定して、標準のボタンとの互換性を重要視しないような場合には良い方法ですが、今回は標準のボタンと差し替えて使いたいので、
極力同じ挙動で、クラシック表示でのボタン上のイメージ表示だけ改善したいと思っています。

もう少し調査してみます。
引用返信 編集キー/
■65136 / inTopicNo.5)  Re[4]: クラシック表示でのボタン上のイメージ表示について
□投稿者/ キム (3回)-(2013/02/07(Thu) 14:51:32)
すみません、名前が文字化けしてしまいました。
No65135 の発言者はキムです。
引用返信 編集キー/
■65449 / inTopicNo.6)  Re[5]: クラシック表示でのボタン上のイメージ表示について
□投稿者/ キム (6回)-(2013/02/26(Tue) 20:37:38)
VS2010 C#(.NET Framework4.0)にアップデートしましたが状況が変わらないため、ボタンにはイメージを使用しないということで問題を回避しました。
本質的な改善ではないですが、一応の解決とします。

以下、まとめです。

現象
クラシック表示にした場合、ボタンを押すとボタン全体が右下に引っ込むような視覚効果がある。
当然、ボタンの外郭とテキストは同じように右下に動く。
ところが、ボタンのイメージは全く動かないので、とても違和感がある。

最小再現手順
1.Windows フォーム アプリケーションを新規作成して、ボタンを貼り付け、Imageプロパティに適当なイメージを設定する。
2.クラシック表示(7の場合はデスクトップ右クリック > 個人設定 > Windows クラシック)にする。
3.作成したWindows フォーム アプリケーションを実行して実行し、ボタンを押す。

回避方法
・ボタンにイメージを使わない。
・クラシック表示での違和感は仕様としてあきらめる。(イメージが動かないのは制限事項であることを仕様として明確化する)
・クラシック表示時はイメージを表示しない仕様とする。
・通常時用と押下時用(右下にずらした)イメージを用意してコードで切り替える。
  > 押下状態の判定が面倒。
  > 実際の状態と食い違う可能性もある。
・Controlを派生して、OnPaint()でボタンの外観を全て自分で描く(オーナードロー)。
  > 押下状態の判定が面倒。
  > 判定と描画を全部自分で行うので食い違いはない。
  > 標準のボタンと挙動が異なる可能性がある。

解決済み
引用返信 編集キー/
■65451 / inTopicNo.7)  Re[6]: クラシック表示でのボタン上のイメージ表示について
□投稿者/ howling (214回)-(2013/02/27(Wed) 10:32:49)
No65449 (キム さん) に返信
>   > 押下状態の判定が面倒。
これって、そのボタンのMouseDownとMouseUpじゃダメなんですかね?
タブで選択後のエンターキーとかも考慮しないといけないかもしれないですが。
そんなに難しいんでしょうか?うーん…。
解決済み
引用返信 編集キー/
■65456 / inTopicNo.8)  Re[7]: クラシック表示でのボタン上のイメージ表示について
□投稿者/ キム (7回)-(2013/02/27(Wed) 14:15:30)
No65451 (howling さん) に返信
> そんなに難しいんでしょうか?うーん…。

言葉足らずですみません。
マウス操作だけなら下記のコードでいけると思います。
でも、これにキーボード操作が加わると結構大変です。
マウスを押したままスペースキー連打とか、スペースキーを押したままマウスボタンを連打とか。
どちらもSystem.Windows.Forms.Buttonでは感覚と合わない奇妙な挙動を示したので、
きちんとあわせ込んだり、破綻なく動作させるように仕様を制定するのは結構面倒だと感じました。

public class MyButton : Control
{
    private PushButtonState pushState_;                         // 現在の押下状態

    public MyButton()
    {
        SetStyle(ControlStyles.StandardDoubleClick, false);
        pushState_ = Enabled ? PushButtonState.Normal : PushButtonState.Disabled;
    }

    private bool Classic
    {
        get { return !(Application.RenderWithVisualStyles && VisualStyleRenderer.IsSupported); }
    }

    protected override void OnVisibleChanged(EventArgs e)
    {
        base.OnVisibleChanged(e);
        pushState_ = Enabled ? PushButtonState.Normal : PushButtonState.Disabled;
        Invalidate();
    }

    protected override void OnEnabledChanged(EventArgs e)
    {
        base.OnEnabledChanged(e);
        pushState_ = Enabled ? PushButtonState.Normal : PushButtonState.Disabled;
        Invalidate();
    }

    protected override void OnMouseDown(MouseEventArgs mevent)
    {
        base.OnMouseDown(mevent);
        pushState_ = PushButtonState.Pressed;
        Invalidate();
    }

    protected override void OnMouseUp(MouseEventArgs mevent)
    {
        base.OnMouseUp(mevent);
        pushState_ = (ClientRectangle.Contains(mevent.Location)) ? PushButtonState.Hot : PushButtonState.Normal;
        Invalidate();
    }

    protected override void OnMouseEnter(EventArgs e)
    {
        base.OnMouseEnter(e);
        pushState_ = PushButtonState.Hot;
        if (!Classic)
        {
            Invalidate();
        }
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        base.OnMouseLeave(e);
        pushState_ = PushButtonState.Normal;
        if (!Classic)
        {
            Invalidate();
        }
    }

    protected override void OnMouseMove(MouseEventArgs mevent)
    {
        base.OnMouseMove(mevent);

        if ((mevent.Button & MouseButtons.Left) == MouseButtons.Left
        && !ClientRectangle.Contains(mevent.Location)
        && pushState_ == PushButtonState.Pressed)
        {
            pushState_ = PushButtonState.Normal;
            Invalidate();
        }
    }

    protected override void OnPaint(PaintEventArgs pe)
    {
        base.OnPaint(pe);
        // pushState_の値に応じて描画
    }

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -