概要
Winformsで自分用のペイントソフトつくるよ! の続き.
まぁ動くかな,とか思ってたらさっそくバグっていたぜ! ……というわけで対処中,っていう日記.
キー操作への対処
マウスドラッグで描画とかしている最中に矢印キーとかに触れると例外で死ぬとかいう大変なことになっていた(キー操作のこと全然考えてなったよ!)
とにかくいきなり矢印キーとかTabキーとかで想定外の操作が行われると困るので,都合が悪い状態ではキーによる GUI 操作を抑制することにした.
普通のキーではなくて矢印キーとかが相手なので,Form の ProcessCmdKey()
をオーバライドして対処するのが良い模様である.
( Form の KeyPreview
プロパティを true にして KeyPress
イベントあたりを使う方法だと,どうにもうまくいかないようであった.先にキー操作がGUIに消費されてしまう."Preview" とは名ばかりである.)
protected override bool ProcessCmdKey( ref System.Windows.Forms.Message Msg, System.Windows.Forms.Keys keys )
{
//先に自前の処理にキー処理の機会を与える.
//戻り値が「処理したよー」と言ってきたら GUI 操作に処理を回さない.
if( 自前ペイントロジック.ProcessKeyInput( keys ) )return true;
return base.ProcessCmdKey( ref Msg, keys );
}
OK,これで描画中にタブが切り替わって死んだりしなくなった.よかった.
……が,これだけだと,Alt キーとかでメニュー操作状態になった際にも操作を抑制してしまうという問題が発覚.
(メニューが一段ドロップダウンしてあれば矢印キーでメニューが操作できるが,メニュー操作状態になっただけの状態では操作できないっていう謎の状態に.)
なので,こんな感じ↓に対処.
Winformsでは(?)メニューとかはフォーカスを得ない特殊な存在なので メニュー.Focused
とかでは判断できないから,MenuStrip
の MenuActivate
イベントと MenuDeactivate
イベントのハンドラでフラグを上げ下げして状態管理する必要がありそう.
//メニュー操作状態か否かを示すフラグ
private bool m_IsInMenuActiveCondition = false;
//フラグの上げ下げ
private void Main_menuStrip_MenuActivate(object sender, EventArgs e){ m_IsInMenuActiveCondition = true; }
private void Main_menuStrip_MenuDeactivate(object sender, EventArgs e){ m_IsInMenuActiveCondition = false; }
protected override bool ProcessCmdKey( ref System.Windows.Forms.Message Msg, System.Windows.Forms.Keys keys )
{
//今現在メニュー操作状態であれば,キー操作は GUI に回す
if( !m_IsInMenuActiveCondition )
{
//先に自前の処理にキー処理の機会を与える.
//戻り値が「処理したよー」と言ってきたら GUI 操作に処理を回さない.
if( 自前ペイントロジック.ProcessKeyInput( keys ) )return true;
}
return base.ProcessCmdKey( ref Msg, keys );
}
コピペの問題点への対処
全く別の話になるが,前回の状態では「自由形状で選択した範囲をコピーすると,それを他のAPPにペーストできない」という問題があったので,そこを解決する.
クリップボードには複数のデータを突っ込めるという話なので,自APP用の固有のデータだけでなく DIB 形式のものも一緒に入れておけばよいらしい.
//(※扱うBitmapは 24bit or 32bit だという前提のコード)
/// <summary>
/// Bitmapをクリップボードにコピーする.
/// ただし,Format32bppArgb の場合には他APPにうまくペーストできる形にはならない
/// </summary>
/// <param name="bmp">クリップボードにコピーするBitmap</param>
public static void CopyBMP_To_Clipboard( Bitmap bmp )
{
if( bmp.PixelFormat == System.Drawing.Imaging.PixelFormat.Format32bppArgb )
{
//※ClipboardはBtimapの透明度をサポートしないらしいので,
//アルファCHがある場合,PNGのデータをクリップボードに入れることで対処するとかいう話.
//この場合,自分は良いけども他のAPPには意味不明だからペーストできないという問題があるが……
var DataObj = new System.Windows.Forms.DataObject();
using( var PngMemStrm = new System.IO.MemoryStream() )
{
//てきとーに"PNG" というフォーマット名で突っ込む
bmp.Save( PngMemStrm, System.Drawing.Imaging.ImageFormat.Png );
DataObj.SetData( "PNG", false, PngMemStrm );
//他のAPPへのペーストを考慮して DIB 形式も入れておく.
//これだと「透明箇所が灰色になった画像」になるようだ.
DataObj.SetData( System.Windows.Forms.DataFormats.Dib, true, bmp );
//
System.Windows.Forms.Clipboard.SetDataObject( DataObj, true );
}
}
else
{ System.Windows.Forms.Clipboard.SetImage( bmp ); }
}
他のAPPにペーストしてみると,透明にしてた部分は「謎のちょっと明るい灰色」になる模様.どうなの?って感じだけど,まぁペーストできないよりはマシだと思うのでOKかな.