3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

System.Windows.Forms の極み PicSum

3
Last updated at Posted at 2025-12-24

PicSumという画像ビューアを作っています。
別に画像ビューアでなくてもよいのですが、長いこと開発しているうちにSystem.Windows.Formsとは思えないようなUIになったため、色々なところを紹介させていただきます。

タイトルバーにUIを組み込む。

001.png

UWPではタイトルバーをカスタマイズできるらしいとのことですが、System.Windows.Forms.Formでは本来できません。
タイトルバーを表示しないウィンドウにすることはできますが、それだと最大化ボタンなどが使用できず、仮にそれを独自実装しても一般的なウィンドウと同じ挙動は再現できません。

どうやって実現しているか?

Win32 MessageWM_NCCALCSIZEを書き換えて実現しています。
方法を見つけるまでは大変でしたが突き詰めれば以下の通りだけです。

protected override void WndProc(ref Message m)
{
    if (m.Msg == WinApiMembers.WM_NCCALCSIZE)
    {
        var nccsp = (WinApiMembers.NCCALCSIZE_PARAMS)Marshal.PtrToStructure<WinApiMembers.NCCALCSIZE_PARAMS>(m.LParam);
        nccsp.rgrc0.left += 8;
        nccsp.rgrc0.right -= 8;
        nccsp.rgrc0.bottom -= 8;
        Marshal.StructureToPtr(nccsp, m.LParam, false);
        return;
    }
    else if (m.Msg == WinApiMembers.WM_NCPAINT ||
        m.Msg == WinApiMembers.WM_NCACTIVATE ||
        m.Msg == WinApiMembers.WM_NCHITTEST ||
        m.Msg == WinApiMembers.WM_SETREDRAW ||
        m.Msg == WinApiMembers.WM_DPICHANGED ||
        m.Msg >= WinApiMembers.WM_DWM_FIRST && m.Msg <= WinApiMembers.WM_DWM_LAST)
    {
        // WM_NCCALCSIZEを処理すると最大化ボタン等が反応しないので、以下の処理で対処する。
        var dwmHandled = WinApiMembers.DwmDefWindowProc(
            m.HWnd, m.Msg, m.WParam, m.LParam, out var result);
        if (dwmHandled == 1)
        {
            m.Result = result;
            return;
        }
    }

    base.WndProc(ref m);
}

Webブラウザのようなタブ操作

タブは後述のファイルリストと同様にPaintイベントで全て描画しています。
それをドラッグアンドドロップで操作しているように描画し、Webブラウザのタブのように切り離しや結合を実現しています。
002.gif

オリジナルのリスト

デフォルトのListBoxListViewでは機能やカスタマイズ性が貧弱なため、Paintイベントで全てを描画しています。
これは以下の数値がわかれば実装できます。もちろんスクロール位置も。

  1. リストコントロールの大きさ
  2. リスト内のスクロール位置
  3. 項目の大きさ
  4. 項目間の間隔
  5. 項目の数
    007.gif

ワイドなコンボボックス

普通のコンボボックスは縦に一列だけですので、項目が増えるとスクロールする必要があります。
そこでグリッドのように項目を配置して、一度に目にする項目の数を増やしています。(賛否あるかもしれませんが)
これは上記のファイルリストを変形して実装しています。
003.gif

画像ファイルの切り替え処理の順番

画像ファイルの読み込み処理は可能な限り高速な方法を採用しています。
が、読み込み処理を非同期化するのは当然としても、素早く切り替えた際にユーザー体験を損なわないため3段階で描画しています。
これらはどの段階でも後続の処理を優先して、いつでもキャンセルできるようにしています。

  1. 画像の大きさの四角を描画
    004.png

  2. 画像を低画質で描画
    003.png

  3. 画像を高画質で描画
    005.png

最後に

興味のある方は Microsoft Store からぜひご利用ください。
Microsoft Store PicSum

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?