问题
I'm using MonoDevelop tool.
I want to make program like below with GTK#;
1. User drags file to program's listView, tableView or whatever
2. Dragged file's list is printed on the program's window
But I'm almost new to GTK# and find the way how to drag and drop,
so I searched information about it and found this link like below.
http://developer.gnome.org/gtkmm-tutorial/3.0/sec-dnd-example.html.en
This is the code I tried to make program link suggested
(This link explains drag and drop in C++ and I had to make it the way like C#)
using Gtk;
using System;
using System.Collections;
using System.Collections.Generic;
namespace DragAndDrop
{
public class SharpApp: Window
{
Button btnDrag;
Label lblDrop;
HBox hbox;
public SharpApp (): base("Title")
{
btnDrag = new Button("Drag Here");
lblDrop = new Label("Drop Here");
hbox = new HBox();
SetDefaultSize(250,200);
SetPosition (Gtk.WindowPosition.Center);
DeleteEvent += (o, args) => Application.Quit ();
// Targets
List<TargetEntry> list
= new List<TargetEntry> ();
list.Add (new TargetEntry
("STRING", TargetFlags.Widget, 0));
list.Add (new TargetEntry
("text/plain", TargetFlags.Widget, 0));
// Drag site -----
// Make btnDrag a DnD drag source:
TargetEntry[] entries = list.ToArray();
TargetEntry[] se = new TargetEntry[] {entries[0]};
Drag.SourceSet (btnDrag, Gdk.ModifierType.ModifierMask,
se, Gdk.DragAction.Copy);
// Connect signals
btnDrag.DragDataGet += delegate
(object o, DragDataGetArgs args) {
Console.WriteLine ("Test");
OnDragDataGet(args.Context,
args.SelectionData,
args.Info,
args.Time);
};
hbox.PackStart (btnDrag);
// Drop site -----
// Make lblDrop a DnD drop destination:
TargetEntry[] de = new TargetEntry[] {entries[1]};
Drag.DestSet (lblDrop, DestDefaults.Drop,
de, Gdk.DragAction.Copy);
// Connect signals
lblDrop.DragDataReceived += delegate
(object o, DragDataReceivedArgs args) {
Console.WriteLine ("Test");
OnDragDataReceived(args.Context,
args.X,
args.Y,
args.SelectionData,
args.Info,
args.Time);
};
// hbox
hbox.PackStart (lblDrop);
Add (hbox);
ShowAll ();
}
// event handlers
protected override void OnDragDataGet
(Gdk.DragContext context, SelectionData sdata,
uint info, uint time)
{
Console.WriteLine ("OnDragDataGet");
string tmp = "I'm data!";
byte[] b = new byte[tmp.Length];
for (int i=0; i<tmp.Length; ++i)
b[i] = (byte)tmp[i];
sdata.Set(sdata.Target, 8, b, tmp.Length);
}
protected override void OnDragDataReceived
(Gdk.DragContext context, int x, int y,
SelectionData sdata, uint info, uint time)
{
Console.WriteLine ("OnDragDataReceived");
int length = sdata.Length;
if ((length>=0) && (sdata.Format==8))
{
Console.WriteLine ("Received \"{0}\" in label",
sdata.Data.ToString());
}
Drag.Finish (context, false, false, time);
}
// main
public static void Main (string[] args)
{
Application.Init ();
new SharpApp();
Application.Run ();
}
}
}
but the result tells me I might be wrong.. I thought the button will be moved
when I drag it, but the button didn't move at all. Is there anyone able to fix my problem?
回答1:
The following example prints into a label (called lblPath) the full path of the files dropped over it:
public partial class MainWindow: Gtk.Window
{
/** Add a label to your project called lblPath **/
public MainWindow () : base (Gtk.WindowType.Toplevel)
{
Build ();
//media type we'll accept
Gtk.TargetEntry [ ] target_table =
new TargetEntry [ ] {
new TargetEntry ("text/uri-list", 0, 0),
new TargetEntry ("application/x-monkey", 0, 1),
};
Gtk.Drag.DestSet (lblPath, DestDefaults.All, target_table, Gdk.DragAction.Copy);
lblPath.DragDataReceived += new Gtk.DragDataReceivedHandler(OnLabelDragDataReceived);
}
void OnLabelDragDataReceived (object sender, Gtk.DragDataReceivedArgs args)
{
if (args.SelectionData.Length > 0) {
byte[] data = args.SelectionData.Data;
string files = System.Text.Encoding.UTF8.GetString (data);
string file;
string[] fileArray = files.Split ('\n');
for (int i = 0; i < fileArray.Length - 1; i++) { //the last element is empty
file = fileArray [i].Replace ("\r", "");
if (file.StartsWith("file://"))
file = file.Substring(7); //for Windows should be 8
lblPath.Text += file + "\n";
}
}
}
}
回答2:
Self answer
I found tutorials about drag and drop here:
https://github.com/mono/gtk-sharp/blob/master/sample/TestDnd.cs
http://my.safaribooksonline.com/book/programming/mono/0596007922/gtksharp/monoadn-chp-4-sect-8
and I made a tutorial of drag and drop myself.
This is drop file tutorial.
using System;
using System.Collections;
using System.Collections.Generic;
// 1. Drop file tutorial
namespace DropFile
{
public class App: Gtk.Window
{
Gtk.Label lbldrop;
public App (): base ("Drop file")
{
this.SetDefaultSize (250, 200);
this.SetPosition (Gtk.WindowPosition.Center);
this.DeleteEvent += OnTerminated;
this.lbldrop = new Gtk.Label ("Drop here!");
Gtk.Drag.DestSet (this.lbldrop, 0, null, 0);
this.lbldrop.DragDrop
+= new Gtk.DragDropHandler
(OnLabelDragDrop);
this.lbldrop.DragDataReceived
+= new Gtk.DragDataReceivedHandler
(OnLabelDragDataReceived);
Gtk.VBox vbox = new Gtk.VBox ();
vbox.PackStart (this.lbldrop, true, true, 0);
this.Add (vbox);
this.ShowAll ();
}
void OnLabelDragDrop (object sender, Gtk.DragDropArgs args)
{
Gtk.Drag.GetData
((Gtk.Widget)sender, args.Context,
args.Context.Targets[0], args.Time);
}
void OnLabelDragDataReceived
(object sender, Gtk.DragDataReceivedArgs args)
{
if (args.SelectionData.Length > 0
&& args.SelectionData.Format == 8) {
byte[] data = args.SelectionData.Data;
string encoded = System.Text.Encoding.UTF8.GetString (data);
// I don't know what last object is,
// but I tested and noticed that it is not
// a path
List<string> paths
= new List<string> (encoded.Split ('\r', '\n'));
paths.RemoveAll (string.IsNullOrEmpty);
paths.RemoveAt (paths.Count-1);
for (int i=0; i<paths.Count; ++i)
{
Console.WriteLine ("Path {0}: {1}", i, paths[i]);
}
}
}
bool Test (string str)
{
return true;
}
void OnTerminated (object sender, EventArgs args)
{
Gtk.Application.Quit ();
}
public static void Main (string[] args)
{
Gtk.Application.Init ();
new App ();
Gtk.Application.Run ();
}
}
}
And this is drag button tutorial.
using System;
// 2. Drag button tutorial
namespace DragButton
{
public class App: Gtk.Window
{
enum StatusType
{
Checked,
NotChecked
}
Gtk.Button btnDrag;
Gtk.Label lblDrop;
bool isChecked;
Gtk.Statusbar sBar;
public App (): base("Drag And Drop Complete")
{
this.SetDefaultSize (250, 200);
this.SetPosition (Gtk.WindowPosition.Center);
this.DeleteEvent += OnTerminated;
this.isChecked = false;
this.sBar = new Gtk.Statusbar ();
sBar.Push ((uint)StatusType.NotChecked, "Not checked");
this.btnDrag = new Gtk.Button ("Drag here");
Gtk.Drag.SourceSet
(this.btnDrag,
Gdk.ModifierType.Button1Mask
| Gdk.ModifierType.Button3Mask,
null,
Gdk.DragAction.Copy | Gdk.DragAction.Move);
this.btnDrag.DragDataGet
+= new Gtk.DragDataGetHandler
(HandleSourceDragDataGet);
this.btnDrag.DragDataDelete
+= new Gtk.DragDataDeleteHandler
(HandleSourceDragDataDelete);
// set drop label as destination
this.lblDrop = new Gtk.Label ("Drop here");
Gtk.Drag.DestSet (this.lblDrop, 0, null, 0);
this.lblDrop.DragMotion
+= new Gtk.DragMotionHandler
(HandleTargetDragMotion);
this.lblDrop.DragDrop
+= new Gtk.DragDropHandler
(HandleTargetDragDrop);
this.lblDrop.DragDataReceived
+= new Gtk.DragDataReceivedHandler
(this.HandleTargetDragDataReceived);
this.lblDrop.DragDrop
+= new Gtk.DragDropHandler
(this.HandleStatBarDragDrop);
Gtk.MenuBar bar = new Gtk.MenuBar ();
Gtk.MenuItem item = new Gtk.MenuItem ("File");
Gtk.Menu menu = new Gtk.Menu ();
item.Submenu = menu;
bar.Append (item);
// accel key
Gtk.AccelGroup ag = new Gtk.AccelGroup ();
this.AddAccelGroup (ag);
item = new Gtk.MenuItem ("Quit");
item.Activated += OnTerminated;
item.AddAccelerator
("activate", ag, new Gtk.AccelKey
(Gdk.Key.Q, Gdk.ModifierType.ControlMask,
Gtk.AccelFlags.Visible));
menu.Append (item);
Gtk.VBox vbox = new Gtk.VBox();
vbox.PackStart (bar, false, false, 0);
Gtk.HBox hbox = new Gtk.HBox ();
hbox.PackStart (this.btnDrag, true, true, 0);
hbox.PackStart (this.lblDrop, true, true, 0);
vbox.PackStart (hbox, true, true, 0);
vbox.PackStart (sBar, false, false, 0);
this.Add (vbox);
this.ShowAll ();
}
void OnTerminated(object sender, EventArgs args)
{
Gtk.Application.Quit ();
}
void HandleSourceDragDataGet
(object sender, Gtk.DragDataGetArgs args)
{
Console.WriteLine ("Source Drag Data Get");
args.SelectionData.Text = "I'm data!";
}
void HandleSourceDragDataDelete
(object sender, Gtk.DragDataDeleteArgs args)
{
Console.WriteLine ("Source Drag Data Delete");
Console.WriteLine ("Delete the data!");
}
void HandleTargetDragMotion
(object sender, Gtk.DragMotionArgs args)
{
Gdk.Drag.Status (args.Context,
args.Context.SuggestedAction,
args.Time);
args.RetVal = true;
}
void HandleTargetDragDrop
(object sender, Gtk.DragDropArgs args)
{
Console.WriteLine ("drop");
if (args.Context.Targets.Length != 0) {
Gtk.Drag.GetData
((Gtk.Widget)sender, args.Context,
args.Context.Targets[0], args.Time);
args.RetVal = true;
}
args.RetVal = false;
}
void HandleTargetDragDataReceived
(object sender, Gtk.DragDataReceivedArgs args)
{
Console.WriteLine ("received");
if (args.SelectionData.Length >= 0
&& args.SelectionData.Format == 8)
{
Console.WriteLine ("Hi!");
Gtk.Drag.Finish (args.Context, true, false, args.Time);
}
Gtk.Drag.Finish (args.Context, false, false, args.Time);
}
void HandleStatBarDragDrop
(object sender, Gtk.DragDropArgs args)
{
isChecked = !isChecked;
if (isChecked)
sBar.Push ((uint)StatusType.Checked, "Checked");
else
sBar.Pop ((uint)StatusType.Checked);
}
public static void Main (string[] args)
{
Gtk.Application.Init ();
new App ();
Gtk.Application.Run ();
}
}
}
来源:https://stackoverflow.com/questions/14273471/drag-and-drop-files-into-program