出会いセンター ドラッグ中に半透明のイメージを表示させる方法(C#)

ドラッグ中に半透明のイメージを表示させる方法

エクスプローラなどのアプリケーションではファイルをドラッグするときに半透明のイメージが一緒に ドラッグされるようになっています。このTipsは、この半透明のイメージを表示させる方法についてです。

半透明なWindowを利用する方法

Formにはその不透明度を設定するOpacityというプロパティがあります。これを利用すれば、所望の ことは容易にできると思われます。

確かに可能ですが、ドラッグ中の小さなイメージごときにFormを使うのは勿体無い気がしますし、 最前面に表示するためにTopMostを設定したり、タスクバーに表示させないようにShowInTaskbar を設定したりと、色々面倒です。更にこのFormを表示したときにはフォーカスも移ってしまうので、 その対策も必要です。簡単にできそうですが、何かと不便なところもありそうです。

Win32 APIに用意されている機能を使う方法

やはりこのような機能はWin32 APIに予め用意されているものです。使用するAPIは以下の5つです。

この他、ImageList_DragShowNolockなどのAPIもありますが、ここでは割愛します。

さて、これらのAPIは名前をみたらその使い方が想像できるようなものばかりです。実際その通りで容易に 所望のことを実現できます。しかし、ひとつ注意することがあります。それは、これらのAPIに渡す 座標です。ImageList_BeginDrag、ImageList_DragMove、ImageList_DragEnter、にはそれぞれ指定された 形式の座標を渡してやる必要があります。

まず、ImageList_BeginDragはドラッグ中に表示されるイメージにおける相対座標を指定します。 つまり、ListBoxの場合GetItemRectangleを使ってドラッグしたいアイテムのRectangleを取得し、 現在あるポインタ座標からその値を引いたものが、イメージの左上からの相対座標になるということです。

一方ImageList_DragMove、ImageList_DragEnterに指定する座標はWindowの左上からの相対座標を渡す必要が あります、ここで注意しなければならないのは、Window全体における相対座標であって、クライアント領域 における相対座標ではないということです。従って、PointToClientは使うことができないということです。 実際には、現在のポインタ座標から、WindowのLeftとTopを引いて算出します。

これらのことにさえ注意すれば、難なく使えると思われます。次にその使用例を示します。 二つのListBox間でテキストのドラッグ&ドロップを行うサンプルです。

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace DragGhostImageSample
{
    /// <summary>
    /// Form1
    /// </summary>
    public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.ListBox lstSource;
        private System.Windows.Forms.ListBox lstDest;
        private System.ComponentModel.IContainer components;
        private System.Windows.Forms.ImageList imageList1;

        // MouseDown時の座標保存変数
        private Point mouseDownPoint = Point.Empty;

        #region コンストラクタ

        public Form1()
        {
            InitializeComponent();
            for(int i=0; i<10; i++)
                lstSource.Items.Add("item" + i.ToString());
        }

        #endregion

        #region Dispose処理

        /// <summary>
        /// 使用されているリソースに後処理を実行します。
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #endregion

        #region Windows フォーム デザイナで生成されたコード
        /// <summary>
        /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディタで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.lstSource = new System.Windows.Forms.ListBox();
            this.lstDest = new System.Windows.Forms.ListBox();
            this.imageList1 = new System.Windows.Forms.ImageList(this.components);
            this.SuspendLayout();
            //
            // lstSource
            //
            this.lstSource.AllowDrop = true;
            this.lstSource.ItemHeight = 12;
            this.lstSource.Location = new System.Drawing.Point(0, 8);
            this.lstSource.Name = "lstSource";
            this.lstSource.Size = new System.Drawing.Size(120, 160);
            this.lstSource.TabIndex = 0;
            this.lstSource.MouseDown += new System.Windows.Forms.MouseEventHandler(this.lstSource_MouseDown);
            this.lstSource.QueryContinueDrag += new System.Windows.Forms.QueryContinueDragEventHandler(this.lstSource_QueryContinueDrag);
            this.lstSource.MouseUp += new System.Windows.Forms.MouseEventHandler(this.lstSource_MouseUp);
            this.lstSource.MouseMove += new System.Windows.Forms.MouseEventHandler(this.lstSource_MouseMove);
            this.lstSource.DragEnter += new System.Windows.Forms.DragEventHandler(this.lstSource_DragEnter);
            this.lstSource.GiveFeedback += new System.Windows.Forms.GiveFeedbackEventHandler(this.lstSource_GiveFeedback);
            //
            // lstDest
            //
            this.lstDest.AllowDrop = true;
            this.lstDest.ItemHeight = 12;
            this.lstDest.Location = new System.Drawing.Point(152, 8);
            this.lstDest.Name = "lstDest";
            this.lstDest.Size = new System.Drawing.Size(120, 160);
            this.lstDest.TabIndex = 1;
            this.lstDest.DragDrop += new System.Windows.Forms.DragEventHandler(this.lstDest_DragDrop);
            this.lstDest.DragEnter += new System.Windows.Forms.DragEventHandler(this.lstDest_DragEnter);
            //
            // imageList1
            //
            this.imageList1.ImageSize = new System.Drawing.Size(16, 16);
            this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
            this.ClientSize = new System.Drawing.Size(272, 173);
            this.Controls.Add(this.lstDest);
            this.Controls.Add(this.lstSource);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
        #endregion

        #region メインエントリポイント

        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }

        #endregion


        #region lstSource側の処理

        private void lstSource_MouseDown(object sender,
                                        System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
                if (((ListBox)sender).IndexFromPoint(e.X, e.Y) >= 0)
                    mouseDownPoint = new Point(e.X, e.Y);
            else
                mouseDownPoint = Point.Empty;
        }

        private void lstSource_MouseMove(object sender,
                                        System.Windows.Forms.MouseEventArgs e)
        {
            if (mouseDownPoint != Point.Empty)
            {
                Rectangle dragRegion = new Rectangle(
                    mouseDownPoint.X - SystemInformation.DragSize.Width / 2,
                    mouseDownPoint.Y - SystemInformation.DragSize.Height / 2,
                    SystemInformation.DragSize.Width,
                    SystemInformation.DragSize.Height);
                if (!dragRegion.Contains(e.X, e.Y))
                {
                    // ListBoxからドラッグ中のアイテムを取得
                    ListBox lst = (ListBox)sender;
                    int itemIndex = lst.IndexFromPoint(mouseDownPoint);
                    if (itemIndex < 0) return;
                    string itemText = (string)lst.Items[itemIndex];

                    // Imageの初期化
                    imageList1.Images.Clear();
                    Rectangle itemRect = lst.GetItemRectangle(itemIndex);
                    imageList1.ImageSize = new Size(itemRect.Width, itemRect.Height);
            
                    // 半透明イメージの元画像を作成、ImageListに追加
                    Bitmap bmp = new Bitmap(itemRect.Width, itemRect.Height);
                    Graphics g = Graphics.FromImage(bmp);
                    g.DrawString(itemText, lst.Font, new SolidBrush(lst.ForeColor), 0, 0);
                    imageList1.Images.Add(bmp);

                    // ImageList_BeginDragにはドラッグする
                    // イメージの中における相対座標を指定する

                    if(DragImage.ImageList_BeginDrag(imageList1.Handle, 0,
                                                     e.X - itemRect.Left,
                                                     e.Y - itemRect.Top))
                    {
                        lstSource.DoDragDrop(itemText, DragDropEffects.Copy);
                        DragImage.ImageList_EndDrag();
                    }
                    mouseDownPoint = Point.Empty;
                }
            }
        }

        private void lstSource_MouseUp(object sender,
                                       System.Windows.Forms.MouseEventArgs e)
        {
            mouseDownPoint = Point.Empty;        
        }

        private void lstSource_DragEnter(object sender,
                                         System.Windows.Forms.DragEventArgs e)
        {
            // ImageList_DragEnterにはクライアント領域における相対座標ではなく
            // タイトルバーなどの非クライアント領域を含むWindowにおける相対座標を指定する
            Point p = this.PointToClient(Cursor.Position);
            int x = Cursor.Position.X - this.Left;
            int y = Cursor.Position.Y - this.Top;
            // ドラッグ中は半透明イメージを表示し続けたいのでImageList_DragEnterには
            // ListBoxのHandleを渡すのでなく、FormのHandleを渡す
            DragImage.ImageList_DragEnter(this.Handle, x, y);
        }

        private void lstSource_GiveFeedback(object sender,
                                           System.Windows.Forms.GiveFeedbackEventArgs e)
        {
            e.UseDefaultCursors = false;
        }

        private void lstSource_QueryContinueDrag(object sender,
                                        System.Windows.Forms.QueryContinueDragEventArgs e)
        {
            // ImageList_DragEnter同様Windowにおける相対座標を指定する
            int x = Cursor.Position.X - this.Left;
            int y = Cursor.Position.Y - this.Top;
            DragImage.ImageList_DragMove(x, y);
        }

        #endregion


        #region lstDest側の処理

        private void lstDest_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
        {
            if(e.Data.GetDataPresent(typeof(string)))
                e.Effect = DragDropEffects.Copy;
            else
                e.Effect = DragDropEffects.None;
        }

        private void lstDest_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
        {
            DragImage.ImageList_DragLeave(this.Handle);
            if(e.Data.GetDataPresent(typeof(string)))
            {
                string itemText = (string) e.Data.GetData(typeof(string));
                ((ListBox)sender).Items.Add(itemText);
            }
        }

        #endregion
    }
}
スナップショット

なお、コード中に使われているDragImageというクラスは単純にWin32 APIを宣言したクラスなので、 サンプルコードを参考にしてください。

無料 出会い系 無料 出会い 無料 出会い 無料 出会い 無料 出会い 無料 出会い 無料 出会い 無料出会い 無料 出会い系 無料 出会い 無料 出会い 無料 出会い 無料 出会い 無料 出会い 無料 出会い 無料 出会い 無料 出会い 無料 出会い 無料 出会い掲示板 アクセスカウンター 無料 出会い 無料 出会い 無料 出会い デリヘル 広島 無料出会い 無料 出会い 無料 出会い 印鑑 アダルト動画 無料 出会い系 無料 出会い 無料 出会い 無料 出会い 無料 出会い 無料出会い 無料 出会い系 無料 出会い 無料 出会い 無料出会い 無料 出会い 無料 出会い オオクワガタ 無料 出会い