DOBON.NETプログラミング道掲示板
(現在 過去ログ2 を表示中)

[ 最新記事及び返信フォームをトピックトップへ ]

■33696 / inTopicNo.1)  ListViewの画像のドラッグアンドドロップ
  
□投稿者/ やす 一般人(1回)-(2017/10/15(Sun) 18:39:32)
  • アイコン環境/言語:[VisalStudio2015] 
    分類:[.NET] 

    ListViewに画像を表示して2つのListViewの間をドラッグアンドドロップで
    移動させたいのですが、移動できるが移動させた画像が渡らないという
    現象が発生しております。

    サンプル開発中なのでソースを添付しておきます
    よろしくお願いします
イメージ
ImageTransporter.zip
/2KB
引用返信 削除キー/
■33697 / inTopicNo.2)  Re[1]: ListViewの画像のドラッグアンドドロップ
□投稿者/ 魔界の仮面弁士 大御所(1087回)-(2017/10/16(Mon) 10:02:13)
  • アイコンNo33696に返信(やすさんの記事)
    > サンプル開発中なのでソースを添付しておきます

    *.cs ファイルしかなく、*.designer.cs が無いので
    開けるように再加工するのが面倒でした…。


    > ListViewに画像を表示して2つのListViewの間をドラッグアンドドロップで
    > 移動させたいのですが、移動できるが移動させた画像が渡らないという
    > 現象が発生しております。

    designer.cs が無いので、コンストラクタだけ弄って補間しましたが、
    こちらの環境では普通に移動されました。
    ImageList の割り当てに問題があるのでは無いですかね。


    public ImageTransporter()
    {
      // フォームに ListView 2 つ(listRoot、listDest)のみ貼った状態です
      // プロパティは位置・サイズ・名前以外は初期値のままとしています。
      // ImageList も貼っていません(下記のコードで生成および割り当てています)

      InitializeComponent();

      // ===> 追加(実験用コード) ===>
      var il = new ImageList() { ImageSize = new Size(32, 32)};
      var rect = new RectangleF(0F, 0F, 32F, 32F);
      using (var f = new Font("MS Gothic", 15F, FontStyle.Regular))
      {
        for (int i = 0; i < 10; i++)
        {
          var bmp = new Bitmap(32, 32);
          using (var g = Graphics.FromImage(bmp))
          {
            g.Clear(Color.LightPink);
            g.DrawString(i.ToString(), f, Brushes.Black, rect);
          }
          il.Images.Add(bmp);
        }
      }
      listRoot.Items.Clear();
      listDest.Items.Clear();
      listRoot.LargeImageList = listDest.LargeImageList = il;
      listDest.AllowDrop = true;
      // <=== 追加(実験用コード) ===
    }
引用返信 削除キー/
■33699 / inTopicNo.3)  Re[2]: ListViewの画像のドラッグアンドドロップ
□投稿者/ やす 一般人(3回)-(2017/10/16(Mon) 12:49:00)
http://VisalStudio2015
  • アイコン返信ありがとうございます。
    追記いたしますと、左から右へ移動する際はうまく動いているように
    みえますが、動かした右から再度左へ移動したときに
    違う画像が移動されるように見えます。
    *.designer.cs等も送付いたします。
    (前回添付忘れてお手数をおかけしてしまい申し訳ございませんでした。)

    よろしくお願いします。


    No33697に返信(魔界の仮面弁士さんの記事)
    > ■No33696に返信(やすさんの記事)
    >>サンプル開発中なのでソースを添付しておきます
    >
    > *.cs ファイルしかなく、*.designer.cs が無いので
    > 開けるように再加工するのが面倒でした…。
    >

イメージ
ImageTransporter_SRC.zip
/4KB
引用返信 削除キー/
■33701 / inTopicNo.4)  Re[3]: ListViewの画像のドラッグアンドドロップ
□投稿者/ 魔界の仮面弁士 大御所(1090回)-(2017/10/16(Mon) 17:41:22)
  • アイコン2017/10/16(Mon) 17:51:19 編集(投稿者)

    No33699に返信(やすさんの記事)
    > *.designer.cs等も送付いたします。
    > (前回添付忘れてお手数をおかけしてしまい申し訳ございませんでした。)

    画像も埋め込んでいるなら、*.resx も同梱しないと開けないですよ…。



    > 追記いたしますと、左から右へ移動する際はうまく動いているように
    現在のコードを、もう一度良く見てください。

    【listDest_DragDrop】
    > lvi.ImageIndex = listDest.Items.Count;
    > listDest.Items.Add(lvi);


    【listRoot_DragDrop】
    > lvi.ImageIndex = listRoot.Items.Count;
    > listRoot.Items.Add(lvi);

    ListViewItem の ImageIndex や ImageKey に渡される値は、
    ImageList の Image を示す情報であるはずです。
    たとえば ImageList にアイテムが 3 つあれば、ImageIndex に
    渡せる値は、-1 / 0 / 1 / 2 の 4 種類です。

    しかし現在のコードは、
     lvi.ImageIndex = 「-1 以上 ImageList の Images.Count 未満」;
    の範囲を示していないので誤りです。代入式の右辺が ImageList の画像数ではなく
    ListView のアイテム数を検査してしまっていますよね。


    それに、移動時に ListView から RemoveAt するコードはあっても、
    ImageList からは RemoveAt していないという点も問題があります。

    ListView の方は、Add と RemoveAt がペアになっていますから、
    画像を左から右、右から左へと何度も何度も何度も往復させたとしても、
    ListView に登録されたアイテムの総数は変化しません。

    しかし ImageList の方は Add しかありませんから、増加する一方です。
    画像を往復させるたびに、同じ画像が幾度も追加されていき、
    ImageList の Images.Count が増加していくことになります。


    ということで、上記を見直せば、改善されるかと思います。

    そもそも、同じフォームなのに左右で別の ImageList を
    使っているのは何故なのでしょうか? 分けたい理由が無いのなら、
    同じインスタンスを共有した方が、ImageIndex の付け直しや
    ImageList のAdd/RemoveAt の手間が省けて楽だと思うのですが…。

    先の私の No33697 のコードでも、両者に同じ ImageList を渡していますね。
     『listRoot.LargeImageList = listDest.LargeImageList = il;』
引用返信 削除キー/
■33702 / inTopicNo.5)  Re[4]: ListViewの画像のドラッグアンドドロップ
□投稿者/ やす 一般人(5回)-(2017/10/17(Tue) 08:30:28)
http://VisalStudio2015
  • アイコン魔界の仮面弁士様
    的確なご指摘ありがとうございます。
    imagelistは共有して、移動したイメージのインデックスを
    取得し、それを割り当てる変更で動作するようになりました

    修正して正しい動作したソースを添付しておきます。


解決み!
イメージ
ImageTransporter_END.zip
/2KB
引用返信 削除キー/
■33703 / inTopicNo.6)  Re[5]: ListViewの画像のドラッグアンドドロップ
□投稿者/ 魔界の仮面弁士 大御所(1091回)-(2017/10/17(Tue) 12:17:20)
  • アイコンNo33702に返信(やすさんの記事)
    > 修正して正しい動作したソースを添付しておきます。
    修正結果のフィードバック、ありがとうございます!

    > [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
    > private static extern Int32 SendMessage(IntPtr hwnd, Int32 wMsg, Int32 wParam, Int32 lParam);

    WPARAM / LPARAM という型は、
     Win16環境では、WPRAM = 16bit、LPARAM = 32bit
     Win32環境では、WPRAM = 32bit、LPARAM = 32bit
     Win64環境では、WPRAM = 64bit、LPARAM = 64bit
    の長さをもちます。
    http://www.wdic.org/w/TECH/WPARAM
    http://www.wdic.org/w/TECH/LPARAM

    そのため SendMessage の 第3・第4 引数は、
    Int32 ではなく IntPtr にするのが望ましいと思います。


    > ListView lbx = (ListView)sender;
    lbx という変数名になっているということは、
    元は ListBox だったのでしょうかね。



    > imagelistは共有して、

    listRoot と listDest で同じような処理が書かれていますが、
    ImageList だけでなく、両者のイベントも共通化できるかと思います。


    // listRoot.MouseMove および listDest.MouseMove の双方に割り当てる
    private void listView_MouseMove(object sender, MouseEventArgs e)
    {
      if (mouseDownPoint == Point.Empty)
      {
        return;
      }
      Rectangle moveRect = new Rectangle(
        mouseDownPoint.X - SystemInformation.DragSize.Width / 2,
        mouseDownPoint.Y - SystemInformation.DragSize.Height / 2,
        SystemInformation.DragSize.Width,
        SystemInformation.DragSize.Height);
      if (moveRect.Contains(e.X, e.Y))
      {
        return;
      }

      ListView lbx = (ListView)sender;
      var items = lbx.SelectedItems.OfType<ListViewItem>().ToArray();
      lbx.AllowDrop = false; // ★
      var dde = lbx.DoDragDrop(items, DragDropEffects.All | DragDropEffects.Link);
      lbx.AllowDrop = true; // ★
      if (dde == DragDropEffects.Move)
      {
        lbx.BeginUpdate();
        foreach (var item in items)
        {
          lbx.Items.Remove(item);
        }
        lbx.EndUpdate();
      }
      mouseDownPoint = Point.Empty;
    }

    // listRoot.DragDrop および listDest.DragDrop の双方に割り当てる
    private void listView_DragDrop(object sender, DragEventArgs e)
    {
      var items = (ListViewItem[])e.Data.GetData(typeof(ListViewItem[]));
      ListView lbx = (ListView)sender;
      lbx.BeginUpdate();
      foreach (var item in items)
    {
      lbx.Items.Add((ListViewItem)item.Clone());
    }
      lbx.EndUpdate();
      SetControlSpacing(lbx, 75, 100);
    }


    一応、MultiSelect が true/false のいずれでも動くようにしてあります。

    なお、★ の行にて AllowDrop を切り替えるコードを書いていますが、
    これは、「自分自身へのドロップ」を禁止するためのものです。
    (不要であれば取り除いてください)

    # 解決済みマークは付けたままにしておきます。
解決み!
引用返信 削除キー/
■33706 / inTopicNo.7)  Re[6]: ListViewの画像のドラッグアンドドロップ
□投稿者/ やす 一般人(6回)-(2017/10/17(Tue) 17:45:39)
http://VisalStudio2015
  • アイコンとても参考になるアドバイスありがとうございます。

    No33703に返信(魔界の仮面弁士さんの記事)
    > そのため SendMessage の 第3・第4 引数は、
    > Int32 ではなく IntPtr にするのが望ましいと思います。
    >
    >>imagelistは共有して、
    >
    > listRoot と listDest で同じような処理が書かれていますが、
    > ImageList だけでなく、両者のイベントも共通化できるかと思います。
    >

    早速取り入れました。
    他の、MouseUpとDragEnteも同じように共有化できました

    ありがとうございます。
解決み!
引用返信 削除キー/
■33707 / inTopicNo.8)  Re[7]: ListViewの画像のドラッグアンドドロップ
□投稿者/ やす 一般人(7回)-(2017/10/17(Tue) 18:02:53)
http://VisalStudio2015
  • アイコン解決済みのあとに、以下の内容を実行することになりました。
    別スレッドにしようかと考えましたが、派生だと思い追加で
    質問しております。
    内容:
    ドラッグアンドドロップで今は、一番下へ配置しているのですが、
    例えば、ドラッグする先に2つ画像があった場合、その間や一番先頭など
    のドラッグする位置にドロップすることは、できますでしょうか?

    別で調査しておりますが、平行して質問を上げさせていただきます。
    よろしくお願いします。
引用返信 削除キー/
■33708 / inTopicNo.9)  Re[8]: ListViewの画像のドラッグアンドドロップ
□投稿者/ 魔界の仮面弁士 大御所(1092回)-(2017/10/17(Tue) 19:06:12)
  • アイコンNo33707に返信(やすさんの記事)
    > ドラッグアンドドロップで今は、一番下へ配置しているのですが、
    > 例えば、ドラッグする先に2つ画像があった場合、その間や一番先頭など
    > のドラッグする位置にドロップすることは、できますでしょうか?

    挿入すべき場所を、ListView の HitTest メソッドで調べた上で、
    .Items.Add での「末尾追加」から .Items.Insert での「挿入」に
    変更してみるのは如何でしょう。
引用返信 削除キー/
■33709 / inTopicNo.10)  Re[9]: ListViewの画像のドラッグアンドドロップ
□投稿者/ やす 一般人(9回)-(2017/10/17(Tue) 22:04:08)
http://VisalStudio2015
  • アイコンHitTestメソッドを使用して、insertにする変更を行ってみましたが
    うまく、Hittestで位置が特定できないです。

    No33708に返信(魔界の仮面弁士さんの記事)
    > ■No33707に返信(やすさんの記事)
    >>ドラッグアンドドロップで今は、一番下へ配置しているのですが、
    >>例えば、ドラッグする先に2つ画像があった場合、その間や一番先頭など
    >>のドラッグする位置にドロップすることは、できますでしょうか?
    >
    > 挿入すべき場所を、ListView の HitTest メソッドで調べた上で、
    > .Items.Add での「末尾追加」から .Items.Insert での「挿入」に
    > 変更してみるのは如何でしょう。

    以下のように変更してみました
    private void listView_DragDrop(object sender, DragEventArgs e)
    {
    var items = (ListViewItem[])e.Data.GetData(typeof(ListViewItem[]));

    ListView lbx = (ListView)sender;
    //ListViewHitTestInfo info = lbx.HitTest(e.X,e.Y);
    //MessageBox.Show(info.Location.ToString());
    Point pReleasesPoint = lbx.PointToClient(new Point(e.X, e.Y));
    //ドロップ位置のアイテムindexを取得 デフォルトは最終行
    int ReleasesItemIndex = lbx.Items.Count;
    if ( lbx.HitTest(pReleasesPoint).Item != null)
    {
    ReleasesItemIndex = lbx.HitTest(pReleasesPoint).Item.Index;
    }


    lbx.BeginUpdate();
    foreach (var item in items)
    {
    lbx.Items.Insert(ReleasesItemIndex, (ListViewItem)item.Clone());
    //lbx.Items.Add((ListViewItem)item.Clone());
    }
    lbx.EndUpdate();


    SetControlSpacing(lbx, 75, 100);
    }


    よろしくお願いします。

引用返信 削除キー/
■33710 / inTopicNo.11)  Re[10]: ListViewの画像のドラッグアンドドロップ
□投稿者/ 魔界の仮面弁士 大御所(1093回)-(2017/10/18(Wed) 13:08:16)
  • アイコンNo33709に返信(やすさんの記事)
    > HitTestメソッドを使用して、insertにする変更を行ってみましたが
    > うまく、Hittestで位置が特定できないです。

    アイテムとアイテムの隙間の座標の場合、
    HitTest では検出されませんのでご注意ください。

    // 位置確認用
    private void listView_DragOver(object sender, DragEventArgs e)
    {
      if (e.Data.GetDataPresent(typeof(ListViewItem[])))
      {
       ListView lbx = (ListView)sender;
       var pt = lbx.PointToClient(Cursor.Position);
       var hitTestIndex = (lbx.HitTest(pt).Item ?? new ListViewItem()).Index;
       var nearestIndex = lbx.InsertionMark.NearestIndex(pt);
       Text = "マウス位置=" + hitTestIndex + "/近傍=" + nearestIndex;
      }
    }
    private void listView_DragLeave(object sender, EventArgs e)
    {
      ResetText();
    }


    > 以下のように変更してみました
    今のままだと、ファイル等のドラッグも受け付けてしまうので、
    DragEnger にも手を加えたほうが良いかと。
     if (e.Data.GetDataPresent(typeof(ListViewItem[])))
     {
       e.Effect = DragDropEffects.Move;
     }
     else
     {
       e.Effect = DragDropEffects.None;
     }

    あと、Move しか許可しないのであれば、DoDragDrop メソッドの時点で
    Copy や Link を付与しておく必要も無いと思います。


    > foreach (var item in items)
    > {
    複数の ListViewItem を .Items.Insert するのなら、
     foreach (var item in items.Reverse())
    の方が良いかもしれません。

    もしも単一アイテムしか渡さないという前提なのであれば、
    そもそも ListViewItem[] ではなく、ListViewItem を渡せば OK かと。


    > lbx.Items.Insert(ReleasesItemIndex, (ListViewItem)item.Clone());

    .Items.Insert した結果については、foreach / for などで
    期待通りの順序で列挙されることまでは確認できました。

    private void button1_Click(object sender, EventArgs e)
    {
      System.Diagnostics.Debug.WriteLine("");
      foreach (ListViewItem item in listRoot.Items)
      {
        System.Diagnostics.Debug.WriteLine(item.ImageIndex + "/" + item.Index);
      }
    }

    また、表示上のアイテムの位置については、
    ListViewItem の Position プロパティで位置を指定できます。
    (Alignment、AutoArrange の設定にもよりますが)


    また、画像付きリストを行単位のアイテムとして列挙したいなら
    そもそも ListView ではなく、TreeView を使った方が良いかもしれません。
    階層表示はいらないので、こんな感じで。

    treeView1.ShowLines = false;
    treeView1.ShowPlusMinus = false;
    treeView1.ShowRootLines = false;
    treeView1.FullRowSelect = 任意;
引用返信 削除キー/
■33713 / inTopicNo.12)  Re[11]: ListViewの画像のドラッグアンドドロップ
□投稿者/ やす 一般人(10回)-(2017/10/19(Thu) 14:24:33)
http://VisalStudio2015
  • アイコン下記、アドバイスありがとうございます
    早速取り入れてみて、検証してみたのですが

    確かに、Botton_Click処理結果を見ると
    正し位置にimageindexが並んでいます

    しかし、なぜか表示されている画像が一致しません。
    imageindexの位置は一番上なのに画像は、下に移動したように見えます
    ※ここまでやれたのでできればこのままlistViewでやりたいと
     考えております。

    DragDropのソースを載せておきます。
    private void listView_DragDrop(object sender, DragEventArgs e)
    {
    var items = (ListViewItem[])e.Data.GetData(typeof(ListViewItem[]));

    ListView lbx = (ListView)sender;
    Point pReleasesPoint = lbx.PointToClient(new Point(e.X, e.Y));

    var pt = lbx.PointToClient(pReleasesPoint);
    var nearestIndex = lbx.InsertionMark.NearestIndex(pt);
    //ドロップ位置のアイテムindexを取得 デフォルトは最終行
    int ReleasesItemIndex = lbx.Items.Count;
    if (nearestIndex != -1)
    {
    ReleasesItemIndex = nearestIndex;
    }


    lbx.BeginUpdate();
    foreach (var item in items.Reverse())
    {
    lbx.Items.Insert(ReleasesItemIndex, (ListViewItem)item.Clone());
    }
    lbx.EndUpdate();


    SetControlSpacing(lbx, 75, 100);
    }

    よろしくお願いします。

引用返信 削除キー/
■33714 / inTopicNo.13)  Re[12]: ListViewの画像のドラッグアンドドロップ
□投稿者/ 魔界の仮面弁士 大御所(1094回)-(2017/10/19(Thu) 14:29:43)
  • アイコンNo33713に返信(やすさんの記事)
    > imageindexの位置は一番上なのに画像は、下に移動したように見えます

    AutoArrange が設定されている場合、Alignment に応じて
    詰められてしまうのか、うまく挿入できないのかも知れません。

    試していませんが、LVM_SETITEMPOSITION32 メッセージを
    SendMessage してみるのはどうでしょうか。
    http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=16449&forum=7
引用返信 削除キー/
■33716 / inTopicNo.14)  Re[13]: ListViewの画像のドラッグアンドドロップ
□投稿者/ やす 一般人(12回)-(2017/10/19(Thu) 18:33:56)
http://VisalStudio2015
  • アイコン参考になるサイトありがとうございました。
    実装してみましたが、私の思う動きではなかったため

    質問しておりました「画像だけが正しく見えない」
    (itemindexとimageindexはあっている)
    を解消するため、listViewをcleanして再度表示させることで
    解決にいたりました。

    予定している表示件数も10件以内のためこの仕様ですすめる
    ことにします。

    細かい対応ありがとうございました。

    これで思うような動きになりました。
    最後に完成したソースを添付しておきます。


解決み!
イメージ
ImageTransporter_END2.zip
/3KB
引用返信 削除キー/
■33717 / inTopicNo.15)  Re[14]: ListViewの画像のドラッグアンドドロップ
□投稿者/ やす 一般人(13回)-(2017/10/20(Fri) 02:52:20)
http://VisalStudio2015
  • アイコン少しバグがありましたので修正しました。
    listRootが空になった後listDestへ画像を
    ドラッグアンドドロップすると例外が発生してました

    修正したものを添付しなおしておきます。

解決み!
イメージ
ImageTransporter_END3.zip
/3KB
引用返信 削除キー/



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

このトピックに書きこむ

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

Mode/  Pass/


- Child Tree -