Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Apprendre le glisser/déposer avec Free Pascal/Lazarus
Partie 1/3, par Gilles Vasseur

Le , par gvasseur58

0PARTAGES

10  0 


Si les utilisateurs de Lazarus savent sans doute que leur EDI prend en charge le glisser-déposer (ou Drag and drop en anglais), peut-être n'imaginent-ils pas la richesse des possibilités qui s'ouvrent à eux. Le travail qui suit entend montrer la diversité des approches et la souplesse d'une panoplie d'outils finalement peu utilisés, et encore ne prétend-il pas à l'exhaustivité !

La première partie expose les techniques de base du glisser-déposer :

http://gilles-vasseur.developpez.com/tutoriels/draganddrop1-techniques-base/


Elle sera prochainement suivie de deux autres parties :

  • la personnalisation du glisser-déposer ;
  • la maîtrise du dessin et des gestionnaires d'événements.


Que pensez-vous de ce tutoriel ?
Dans quelles circonstances utilisez-vous le glisser-déposer ?

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de thewolf
Membre habitué https://www.developpez.com
Le 14/05/2017 à 14:05
Bonjour.

Étant donné un site web où il faut charger une image. Ce site propose deux possibilités : soit cliquer sur un bouton, ce qui affiche un dialogue d'ouverture de fichier permettant de naviguer sur son disque dur jusqu'au fichier souhaité, soit effectuer un glisser-déposer du gestionnaire de fichiers vers une zone de saisie.

Il y a quelque temps, j'ai donc cherché (sans trouver !) comment utiliser cette deuxième option pour indiquer le fichier à charger à partir d'un programme développé avec Lazarus (le programme détermine à partir d'un certain nombre de critères le chemin complet du fichier).

Je profite de votre tutoriel sur le glisser-déposer pour reprendre ce sujet. Si vous avez une idée, merci d'avance.
1  0 
Avatar de gvasseur58
Responsable Lazarus & Pascal https://www.developpez.com
Le 15/05/2017 à 8:22
Citation Envoyé par thewolf Voir le message

Étant donné un site web où il faut charger une image.
Bonjour,

Vous parlez de bouton à cliquer et de site Web : en quoi est écrit ce site ?
S'il s'agissait d'une application de bureau Lazarus autonome, il suffirait d'appliquer ce qui est décrit dans la première partie du tutoriel.
S'il s'agit de HTML (HTML 5 accompagné de JavaScript par exemple), le problème peut (sans doute) être résolu, mais il faudrait plutôt s'adresser au forum adéquat .
Il se peut aussi que j'aie mal compris le problème...
1  0 
Avatar de Jipété
Expert éminent sénior https://www.developpez.com
Le 18/05/2017 à 23:18
Bonsoir,
Citation Envoyé par thewolf Voir le message
la cible doit être un site internet (plus précisément une zone ad hoc du site).

Exemple :
Non.
J'ai fait afficher google images dans mon navigateur sous Linux, j'ai pris un fichier .jpg sur le bureau, je l'ai tiré jusque sur la page affichée, pas dans la zone indiquée par le texte ("faire glisser une image ici", c'est le "ici" qui induit en erreur), et dès l'entrée de la souris dans le navigateur l'icône du pointeur change, ainsi que le texte de google, qui affiche du coup l'image ci-dessus.
Suffit de lâcher" l'image et hop !, elle est affichée.

Citation Envoyé par thewolf Voir le message
au survol, l'apparence du site change et quand on relâche, le site charge la photo ...
Non !
Le navigateur charge la photo comme un fichier local ("file:///chemin/fichier.ext" dans la barre d'adresse) en remplaçant purement et simplement la page affichée : le site est perdu.
Je le sais parce que la manip fonctionne également avec un vieux site tout moche dont je suis l'admin et pour lequel je sais très bien qu'il n'y a pas de drag-and-drop de codé, que ce soit en javascript, css ou autre.

Il suffirait donc, en s'inspirant du code proposé par Gilles (et je l'avoue humblement, je ne l'ai pas regardé), de détecter comme cible la présence d'un navigateur et ça devrait le faire.

Mais ça le fera aussi pour n'importe quel navigateur affichant n'importe quel site, à moins de faire une détection du titre affiché dans la barre de titre, justement, de la fenêtre du navigateur.

Maintenant, si on lâche l'image sur la zone "faire glisser une image ici", je vois passer en bas de la fenêtre un javascript(void) qui indique que "quelque chose" a pris la main, mal, car il ne se passe rien...
Ça a mieux fonctionné dans la grande zone "Déposez une image ici" (image bien détectée, infos remontées) -- peut-être lié à des problèmes de cache ou autre...
1  0 
Avatar de Jipété
Expert éminent sénior https://www.developpez.com
Le 30/06/2017 à 20:00
Bonsoir,

je trouve le § "III-A Travail entre deux contrôles" pas très clair...

1re phrase, pas grand chose, il manque juste "de" : "depuis le gestionnaire fichiers"

2e phrase c'est plus ennuyeux car on dirait qu'il manque des mots au tout début.
Pour moi, Le contrôle dont le contenu doit être autorisé à le faire me fait poser la question "faire quoi ?", alors j'improvise ça :
Le contrôle dont le contenu "va être tiré" doit être autorisé à le faire en vérifiant que sa propriété DragKind est bien à sa valeur par défaut,
tiré ou déplacé ou lâché, etc.

3e phrase, je me demande si ça n'est pas l'inverse :
Du côté du contrôle qui va accepter de déposer du contenu, --> Du côté du contrôle qui va accepter de recevoir du contenu,
Si je me trompe, alors peut-être remplacer "déposer" par "exporter" afin de lever toute ambiguïté ?
1  0 
Avatar de gvasseur58
Responsable Lazarus & Pascal https://www.developpez.com
Le 05/07/2017 à 18:25
Bonjour Jipété,

Citation Envoyé par Jipété Voir le message
Bonsoir,
je trouve le § "III-A Travail entre deux contrôles" pas très clair...
Tu es trop indulgent, car ce début de chapitre est devenu illisible par ma faute, je le confesse . Claude Leloup avait tout revu et corrigé avec la rigueur qu'on lui connaît et j'ai fait une mauvaise manipulation qui a gommé certaines des corrections.

J'espère que la mise à jour proposée convient à présent.

Merci

Gilles
1  0 
Avatar de thewolf
Membre habitué https://www.developpez.com
Le 15/05/2017 à 21:40
Bonjour. Merci pour votre réponse.

Il s'agit d'un site web auquel il faut fournir des images. C'est possible en faisant un glisser-déposer depuis le gestionnaire de fichiers vers une zone du site. Ce site est en HTML5 + javascript et, en ayant "fouillé" dans le code source, il utilise pour ce faire un produit appelé "plupload" mais tout cela n'est pas a priori important.

En effet, mon raisonnement est le suivant :

- en faisant un glisser-déposer sur la zone du site prévue à cet effet, le site (plus précisément le plugin "plupload" reçoit l'information suivante : l'utilisateur de l'ordinateur a fait un glisser-déposer en fournissant par exemple l'information suivante : "c:\data\monfichier.jpg".

- Lazarus sait comment traiter ce genre d'information, c'est l'objet de votre premier chapitre "glisser-déposer depuis le gestionnaire de fichiers" : le programme créé va diagnostiquer qu'il a reçu un signal de cette nature, y réagir et en déterminer le contenu (le chemin du ou des fichiers déposés). Donc il devrait savoir comment le créer.

- mon souhait est donc, à l'intérieur de mon programme écrit en Lazarus, de pouvoir simuler ce que fait le gestionnaire de fichiers, par exemple : je fais un glisser-déposer depuis un TLabel ou un Bouton vers la zone "sensible" du site et cela envoie la même information que celle fournie par le gestionnaire de fichiers à savoir dans mon exemple précédent "c:\data\monfichier.jpg", sachant que le nom du fichier est déterminé par le programme en fonction de certains critères ("monfichier" pouvant valoir "img2451" ou "img3727" ou ...)

J'espère avoir été clair.
Bonne soirée

PS : je peux vous fournier le nom du site si vous le souhaitez mais ce n'est pas pertinent, le problème étant général (par exemple Google - Recherche par image).
0  0 
Avatar de gvasseur58
Responsable Lazarus & Pascal https://www.developpez.com
Le 17/05/2017 à 14:06
Bonjour,

Citation Envoyé par thewolf Voir le message

mon souhait est donc, à l'intérieur de mon programme écrit en Lazarus, de pouvoir simuler ce que fait le gestionnaire de fichiers, par exemple : je fais un glisser-déposer depuis un TLabel ou un Bouton vers la zone "sensible" du site et cela envoie la même information que celle fournie par le gestionnaire de fichiers à savoir dans mon exemple précédent "c:\data\monfichier.jpg", sachant que le nom du fichier est déterminé par le programme en fonction de certains critères ("monfichier" pouvant valoir "img2451" ou "img3727" ou ...)
Si j'ai bien compris, voici une unité qui permet de charger une image depuis l'intitulé (Caption) d'un TLabel. La fiche ne contient qu'un TLabel nommé lblFile dont la propriété Caption vaut le nom de l'image (fichier avec son chemin) à afficher et une TImage nommée imgMain dont la propriété Stretch a été mise à True pour l'étirer.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
unit main;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    imgMain: TImage;
    lblFile: TLabel;
    procedure ImgMainDragDrop(Sender, Source: TObject; X, Y: Integer);
    procedure ImgMainDragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.ImgMainDragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
  Accept := (Source is TLabel);
end;

procedure TForm1.ImgMainDragDrop(Sender, Source: TObject; X, Y: Integer);
begin
  imgMain.Picture.LoadFromFile((Source as TLabel).Caption);
end;

end.
Pour que cela fonctionne, il faut bien sûr mettre la propriété DragMode du TLabel à dmAutomatic.
0  0 
Avatar de thewolf
Membre habitué https://www.developpez.com
Le 17/05/2017 à 15:31
Bonjour.

Je suis désolé car je pensais avoir été clair mais ce n'est visiblement pas le cas.

A priori, dans un drag and drop, il y a une source et une cible. Je veux que la source soit mon programme écrit en Lazarus mais la cible doit être un site internet (plus précisément une zone ad hoc du site).

Exemple :


Google Images accepte le glisser-déposer (je cite : "Faire glisser une image ici". Cela fonctionne depuis le gestionnaire de fichiers, également depuis le bureau : au survol, l'apparence du site change et quand on relache, le site charge la photo ...

Comme écrit précédemment, j'aimerais simuler ce que fait le gestionnaire de fichiers. Je démarre le drag and drop de mon programme (le TLabel dans votre exemple) mais je veux relâcher sur le site (Google Images dans mon exemple) et non sur un autre contrôle du programme (TImage dans votre exemple). Mais le "dragover" n'est même pas diagnostiqué par le navigateur. De plus, je ne vois pas comment intégrer l'information à transmettre au départ.

Donc, en résumé, je veux démarrer un glisser-déposer depuis mon programme et que, quand je vais relâcher au-dessus d'un navigateur (Google Images dans mon exemple mais cela doit fonctionner avec tout site qui l'accepte), il soit reconnu par le site et transmette une information particulière (ici une chaine de caractères représentant le chemin d'un fichier image). Exactement ce qui se passe si je fais un glisser-déposer du gestionnaire de fichiers vers le navigateur.

Encore merci.
0  0 
Avatar de gvasseur58
Responsable Lazarus & Pascal https://www.developpez.com
Le 17/05/2017 à 19:25
Si, si, nous allons réussir à nous comprendre .

Le cas de figure décrit est celui que j'écarte explicitement (au moins à court terme), car il n'existe pas de techniques multiplateformes simples pour réaliser ce que vous décrivez.

Voici une unité (en anglais) décrivant une solution pour Windows. Elle permet de déposer du texte à partir d'une application vers une zone de contrôle de type TEdit. Elle est extraite d'une page du wiki free pascal :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  Windows, ActiveX, ComObj;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm, IDropTarget)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    // IDropTarget
    function DragEnter(const dataObj: IDataObject; grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HResult;StdCall;
    function DragOver(grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HResult;StdCall;
    function DragLeave: HResult;StdCall;
    function Drop(const dataObj: IDataObject; grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD):HResult;StdCall;
    // IUnknown
    // Ignore referance counting
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  public
    { public declarations }
  end;
 
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  OleInitialize(nil);
  OleCheck(RegisterDragDrop(Handle, Self));
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  RevokeDragDrop(Handle);
  OleUninitialize;
end;
 
function TForm1.DragEnter(const dataObj: IDataObject; grfKeyState: DWORD;
  pt: TPoint; var dwEffect: DWORD): HResult; StdCall;
begin
  dwEffect := DROPEFFECT_COPY;
  Result := S_OK;
end;
 
function TForm1.DragOver(grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD
  ): HResult; StdCall;
begin
  dwEffect := DROPEFFECT_COPY;
  Result := S_OK;
end;
 
function TForm1.DragLeave: HResult; StdCall;
begin
  Result := S_OK;
end;
 
function TForm1._AddRef: Integer; stdcall;
begin
   Result := 1;
end;
 
function TForm1._Release: Integer; stdcall;
begin
   Result := 1;
end;
 
function TForm1.Drop(const dataObj: IDataObject; grfKeyState: DWORD;
  pt: TPoint; var dwEffect: DWORD): HResult; StdCall;
var
  aFmtEtc: TFORMATETC;
  aStgMed: TSTGMEDIUM;
  pData: PChar;
begin
  {Make certain the data rendering is available}
  if (dataObj = nil) then
    raise Exception.Create('IDataObject-Pointer is not valid!');
  with aFmtEtc do
  begin
    cfFormat := CF_TEXT;
    ptd := nil;
    dwAspect := DVASPECT_CONTENT;
    lindex := -1;
    tymed := TYMED_HGLOBAL;
  end;
  {Get the data}
  OleCheck(dataObj.GetData(aFmtEtc, aStgMed));
  try
    {Lock the global memory handle to get a pointer to the data}
    pData := GlobalLock(aStgMed.hGlobal);
    { Replace Text }
    Memo1.Text := pData;
  finally
    {Finished with the pointer}
    GlobalUnlock(aStgMed.hGlobal);
    {Free the memory}
    ReleaseStgMedium(aStgMed);
  end;
  Result := S_OK;
end;
 
 
end.
Il faudrait l'adapter à la situation que vous avez décrite . Le problème est que la réception doit se faire côté web et donc que c'est là que doit de régler le problème du lâcher...
Notez que ce genre de problème est plutôt délicat à résoudre : il suffit d'étudier la bibliothèque développée pour Delphi pour s'en rendre compte (encore une fois, celle proposée ne fonctionne que sous Windows).

Cordialement,

Gilles
0  0 
Avatar de thewolf
Membre habitué https://www.developpez.com
Le 18/05/2017 à 20:07
Bonjour.
Le cas de figure décrit est celui que j'écarte explicitement (au moins à court terme), car il n'existe pas de techniques multiplateformes simples pour réaliser ce que vous décrivez.
Oui, j’avais bien relevé au début de votre tutoriel que le glisser-déposer entre applications n'y serait pas abordé pour les raisons mentionnées. Je me suis cependant permis d'exposer mon souhait, espérant que vous auriez une réponse pour un sous-ensemble (envoi d'une chaine de caractères vers un navigateur, éventuellement uniquement pour Windows) du cas général.

J'ai bien trouvé sur le wiki de free pascal l'unité que vous avez indiquée mais il s'agit malheureusement d'importer du texte vers l'application Lazarus et non de l'exporter ...
You can drag and drop e.g. text from another application (e.g.t notepad) to a control on your application. The way this is implemented is platform-dependent.
Windows

This code lets you drag and drop selected text from other applications onto an edit control.
Toujours intéressant à connaître, il faudra que je teste ... mais cela commence bizaremment, que penser de cette ligne ?
TForm1 = class(TForm, IDropTarget)
Pair ailleurs:
Le problème est que la réception doit se faire côté web et donc que c'est là que doit de régler le problème du lâcher...
Sauf que c'est impossible, sauf si le but était de déposer sur une application qu'on aurait développée !
Comme exposé précédemment, je pensais naïvement que puisque Lazarus sait réagir (à) et traiter un glisser-déposer depuis l'explorateur de fichiers, il devrait être possible d'envoyer le même genre de signal dans l'autre sens. En fait, cela l'est (au moins pour Windows) puisque vous avez mentionné une bibliothèque développée pour Delphi. Je partage votre avis, cela semble bien compliqué ... Est-il envisagé de porter cette bibliothèque vers Lazarus ?

Cordialement.

Christian

PS : merci pour vos tutoriels très intéressants
0  0