在VB.NET中實(shí)現(xiàn)拖放操作
2024-07-10 13:01:28
供稿:網(wǎng)友
第一次在csdn上發(fā)文章,希望大家?guī)兔κ箘彭?鼓勵(lì)一下新手,謝謝 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/vbtchimpdragdrop.asp 在vb.net中實(shí)現(xiàn)拖放操作 implementing drag and drop in visual basic .net steve hoag visual basic® .net team microsoft corporation september 2003 摘要:這篇文章闡述了如何在vb.net中實(shí)現(xiàn)拖放操作 緒論 windows用戶一般分為兩類:一類習(xí)慣用鍵盤(pán)操作,一類習(xí)慣用鼠標(biāo)操作。程序員們?cè)诰幊虝r(shí)一般會(huì)提供快捷鍵(在命令或字母中加下劃線)或快捷方式(用ctrl加字母的組合)來(lái)照顧到那些習(xí)慣鍵盤(pán)的用戶,但是那些鼠標(biāo)用戶卻被忽略了。因?yàn)槌绦騿T們一般都習(xí)慣用鍵盤(pán),所以他們這種重視鍵盤(pán)操作的特點(diǎn)是可以理解的,但是每個(gè)程序員也應(yīng)該考慮到提供鼠標(biāo)支持。鼠標(biāo)用戶所期望的一件事就是能夠在應(yīng)用程序中實(shí)現(xiàn)拖放。如果你注意到一些大型應(yīng)用程序或windows自身的話,拖放操作幾乎隨處可見(jiàn)。例如,用戶可能已經(jīng)習(xí)慣了在windows資源管理器中拖放文件,或在word中拖放文本等操作了。盡管拖放操作隨處可見(jiàn),但是只有極少數(shù)程序員在他們所編寫(xiě)的程序中實(shí)現(xiàn)拖放功能,最可能的原因是他們認(rèn)為實(shí)現(xiàn)拖放可能比想象的還要難。這篇文章列舉了如何在窗體內(nèi)、窗體之間,甚至應(yīng)用程序之間移動(dòng)文本、圖片或者文件的例子,顯示了在vb.net中實(shí)現(xiàn)拖放是非常容易得。拖放如何進(jìn)行拖放實(shí)際上就如同用鼠標(biāo)復(fù)制粘帖,因此你必須有一個(gè)可以復(fù)制或移動(dòng)的源,也要有一個(gè)可以粘貼的目的地。在這兩個(gè)操作過(guò)程中,數(shù)據(jù)是保存在內(nèi)存中的。復(fù)制粘貼用的是剪切版,而拖放用的卻是一種本質(zhì)上是私有剪切板的dataobject的對(duì)象。下面是典型的托放操作的時(shí)間序列: 1、拖(dragging)是通過(guò)調(diào)用源控件的dodragdrop方法來(lái)初始化的,dodragdrop有兩個(gè)參數(shù) data,指定將要傳送的數(shù)據(jù) allowedeffects,指定允許進(jìn)行的操作(復(fù)制或移動(dòng))這樣自動(dòng)創(chuàng)建了一個(gè)新的dataobject對(duì)象 2、接下來(lái)就依次激發(fā)了givefeedback事件。在大多數(shù)情況下,你并不需要擔(dān)心givefeedback事件,然而你如果想自定義拖放過(guò)程中的鼠標(biāo)指針的話,你可以在這些地方加上你的代碼。 3、任何有allowdrop屬性而且被設(shè)置成true的控件都是隱含的drop對(duì)象。allowdrop屬性可以在設(shè)計(jì)時(shí)的屬性窗口中進(jìn)行設(shè)置,也可以在form_load事件自動(dòng)加載。 4、當(dāng)鼠標(biāo)移到某個(gè)控件時(shí),就同時(shí)激發(fā)了這個(gè)控件的dragenter事件。getdatapresent方法是用來(lái)確認(rèn)拖過(guò)來(lái)的數(shù)據(jù)是否適合目標(biāo)控件,effect屬性是用來(lái)顯示適當(dāng)?shù)氖髽?biāo)指針。 5、如果用戶在有效的目標(biāo)控件上釋放鼠標(biāo),就同時(shí)激發(fā)了dragdrop事件。dragdrop事件句柄中的代碼從dataobject對(duì)象中釋放數(shù)據(jù)并把它顯示在目標(biāo)控件中。從vb6到vb.net有何變化?(略)拖放文本拖放操作的一個(gè)很簡(jiǎn)單然而很有用的情形是從一個(gè)textbox控件復(fù)制文本到另一個(gè)textbox控件。當(dāng)然你可以只用鍵盤(pán)就能實(shí)現(xiàn)(ctrl + c and ctrl + v),然而拖放更簡(jiǎn)單因?yàn)樗鼉H需要鼠標(biāo)的移動(dòng)就可以完成。 1、向一個(gè)窗體中添加兩個(gè)文本框,并把第二個(gè)textbox控件的allowdrop屬性設(shè)置成true,添加如下代碼。 private mouseisdown as boolean = false private sub textbox1_mousedown(byval sender as object, byval e as _ system.windows.forms.mouseeventargs) handles textbox1.mousedown ' set a flag to show that the mouse is down. mouseisdown = true end sub private sub textbox1_mousemove(byval sender as object, byval e as _ system.windows.forms.mouseeventargs) handles textbox1.mousemove if mouseisdown then ' initiate dragging. textbox1.dodragdrop(textbox1.text, dragdropeffects.copy) end if mouseisdown = false end sub private sub textbox2_dragenter(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles textbox2.dragenter ' check the format of the data being dropped. if (e.data.getdatapresent(dataformats.text)) then ' display the copy cursor. e.effect = dragdropeffects.copy else ' display the no-drop cursor. e.effect = dragdropeffects.none end if end sub private sub textbox2_dragdrop(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles textbox2.dragdrop ' paste the text. textbox2.text = e.data.getdata(dataformats. end sub 在上面的例子中,mousedown事件是用來(lái)判斷鼠標(biāo)是否按下的,mousemove事件中用到了dodragdrop方法。盡管你可以在mousedown事件中來(lái)初始化drag,然而這么做會(huì)帶來(lái)出人意料之外的結(jié)果。在用戶點(diǎn)擊控件時(shí),將顯示no-drag 指針。dodragdrop方法有兩個(gè)參數(shù) data,這個(gè)例子中代表的是第一個(gè)textbox的text屬性。 allowedeffects,這個(gè)例子中是只允許復(fù)制。在mousemove事件中mouseisdown標(biāo)志設(shè)置成了false,盡管在這個(gè)例子沒(méi)有必要,但是如果你有很多控件支持拖放時(shí),你將會(huì)得到一個(gè)運(yùn)行時(shí)例外。在dragenter事件中,getdatapresent方法檢查正在拖動(dòng)的數(shù)據(jù)格式,在本例中是文本,所以effect屬性設(shè)置成復(fù)制,同時(shí)也顯示copy指針。在dragdrop事件中,getdata方法用來(lái)從dataobject中獲得文本,并把它送給目標(biāo)文本框。拖動(dòng)圖片盡管拖放圖片并不像拖放文本那樣經(jīng)常用到,然而它在許多應(yīng)用程序中仍然是很有用的。實(shí)際上這兩者之間也沒(méi)有什么不同,只不過(guò)是數(shù)據(jù)類型發(fā)生了變化而已。 1、 在form中添加兩個(gè)picturebox控件。 2、 在代碼窗體中添加如下代碼 private sub form1_load(byval sender as system.object, byval e as _ system.eventargs) handles mybase.load ' enable dropping. picturebox2.allowdrop = true end sub private sub picturebox1_mousedown(byval sender as object, byval e as _ system.windows.forms.mouseeventargs) handles picturebox1.mousedown if not picturebox1.image is nothing then ' set a flag to show that the mouse is down. m_mouseisdown = true end if end sub private sub picturebox1_mousemove(byval sender as object, byval e as _ system.windows.forms.mouseeventargs) handles picturebox1.mousemove if m_mouseisdown then ' initiate dragging and allow either copy or move. picturebox1.dodragdrop(picturebox1.image, dragdropeffects.copy or _ dragdropeffects.move) end if m_mouseisdown = false end sub private sub picturebox2_dragenter(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles picturebox2.dragenter if e.data.getdatapresent(dataformats.bitmap) then ' check for the ctrl key. if e.keystate = 9 then e.effect = dragdropeffects.copy else e.effect = dragdropeffects.move end if else e.effect = dragdropeffects.none end if end sub private sub picturebox2_dragdrop(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles picturebox2.dragdrop ' assign the image to the picturebox. picturebox2.image = e.data.getdata(dataformats.bitmap) ' if the ctrl key is not pressed, delete the source picture. if not e.keystate = 8 then picturebox1.image = nothing end if end sub 注意到上面的例子中第二個(gè)picturebox控件的allowdrop屬性是在form1_load事件中設(shè)置的,這是因?yàn)樵O(shè)計(jì)時(shí)picturebox并沒(méi)有allowdrop屬性。在mousedown事件中,代碼首先檢測(cè)是否有要賦給picturebox的圖片;如果沒(méi)有的話,當(dāng)你移動(dòng)圖片后,接下來(lái)的click將引發(fā)一個(gè)意外。還應(yīng)該注意到的是在dragenter和dragdrop事件中代碼檢測(cè)ctrl鍵是否被按下,從而決定是否是復(fù)制還是移動(dòng)圖片。為什么值會(huì)不同呢?在dragenter事件中,當(dāng)鼠標(biāo)左鍵按下時(shí),產(chǎn)生的值是1,在加上ctrl的值8,從而值為9。見(jiàn)keystate枚舉列表drageventargs.keystate property(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsdrageventargsclasskeystatetopic.asp)。到目前為止,這兩個(gè)例子處理的都是同一窗體不同控件間的拖放,然而在同一應(yīng)用程序的不同窗體上同樣適用。拖動(dòng)文件在windows中拖放通常是復(fù)制或移動(dòng)文件,windows完全支持該功能,而且對(duì)許多用戶來(lái)說(shuō)這也是操作文件的優(yōu)選方式。除此之外,用戶已經(jīng)習(xí)慣了把文件拖動(dòng)到一個(gè)程序來(lái)打開(kāi)文件的方式,像拖動(dòng)一個(gè)doc文件到word來(lái)打開(kāi)。在這個(gè)例子中用從windows資源管理器拖來(lái)的文件來(lái)操作listbox控件。向窗體中添加一個(gè)listbox控件,并設(shè)置其allowdrop屬性為true,并添加如下代碼: private sub listbox1_dragenter(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles listbox1.dragenter if e.data.getdatapresent(dataformats.filedrop) then e.effect = dragdropeffects.all end if end sub private sub listbox1_dragdrop(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles listbox1.dragdrop if e.data.getdatapresent(dataformats.filedrop) then dim myfiles() as string dim i as integer ' assign the files to an array. myfiles = e.data.getdata(dataformats.filedrop) ' loop through the array and add the files to the list. for i = 0 to myfiles.length - 1 listbox1.items.add(myfiles(i)) next end if end sub 你可能已經(jīng)注意到了dragenter事件中的effect屬性被設(shè)置成dragdropeffects.all。因?yàn)槲募旧聿⒉皇钦娴木捅粡?fù)制或移動(dòng)了,因此源控件設(shè)置成哪個(gè)allowedeffects并沒(méi)有關(guān)系,所以指定all對(duì)任何filedrop都可以。在上面的例子中filedrop格式包含了每個(gè)被拖動(dòng)文件的全路徑。下面的例子講述了拖放的一個(gè)特殊情況:在兩個(gè)列表間來(lái)回拖放。表間拖放拖放的另一個(gè)情況是從一個(gè)列表移動(dòng)項(xiàng)目到另一個(gè)列表。這種情況下拖放將變得更加簡(jiǎn)單。向窗體中添加兩個(gè)listview控件,并把他們的allowdrop、multiselect、view屬性分別設(shè)置成true、true、list。并添加如下代碼: private sub listview_itemdrag(byval sender as object, byval e as _ system.windows.forms.itemdrageventargs) handles listview1.itemdrag, _ listview2.itemdrag dim myitem as listviewitem dim myitems(sender.selecteditems.count - 1) as listviewitem dim i as integer = 0 ' loop though the selecteditems collection for the source. for each myitem in sender.selecteditems ' add the listviewitem to the array of listviewitems. myitems(i) = myitem i = i + 1 next ' create a dataobject containg the array of listviewitems. sender.dodragdrop(new _ dataobject("system.windows.forms.listviewitem()", myitems), _ dragdropeffects.move) end sub private sub listview_dragenter(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles listview1.dragenter, _ listview2.dragenter ' check for the custom dataformat listviewitem array. if e.data.getdatapresent("system.windows.forms.listviewitem()") then e.effect = dragdropeffects.move else e.effect = dragdropeffects.none end if end sub private sub listview_dragdrop(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles listview1.dragdrop, _ listview2.dragdrop dim myitem as listviewitem dim myitems() as listviewitem = _ e.data.getdata("system.windows.forms.listviewitem()") dim i as integer = 0 for each myitem in myitems ' add the item to the target list. sender.items.add(myitems(i).text) ' remove the item from the source list. if sender is listview1 then listview2.items.remove(listview2.selecteditems.item(0)) else listview1.items.remove(listview1.selecteditems.item(0)) end if i = i + 1 next end sub 你可能不明白為什么這個(gè)例子中用的是listview控件而不是listbox控件,這個(gè)問(wèn)題題的好,因?yàn)閘istbox控件不支持多項(xiàng)拖放。 listview和treeview控件有個(gè)itemdrag事件。上面的例子中,一個(gè)itemdrag事件句柄覆蓋了兩個(gè)控件,并在列在handles從句。sender參數(shù)表明哪個(gè)控件正在初始化drag。因?yàn)閐ataformats類沒(méi)有l(wèi)istviewitem類型成員,數(shù)據(jù)必須傳遞給一個(gè)系統(tǒng)類型。itemdrag創(chuàng)建了一個(gè)listviewitem類型的數(shù)組,并用一個(gè)循環(huán)來(lái)遍歷selecteditem集合。在dodragdrop方法中,創(chuàng)建了一個(gè)新的dataobject并用數(shù)組來(lái)來(lái)對(duì)它進(jìn)行操作??梢杂眠@種方法來(lái)拖放任何系統(tǒng)類型。結(jié)論:正像你從這些例子中所看到的一樣,為應(yīng)用程序添加拖放操作并不是很難。當(dāng)你理解了這些基本的技巧后,你就可以為你自己的程序添加拖放的代碼了