Deplacement (drag&drop) de la form différent selon les machines :-* [Résolu]

cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention - 13 mars 2006 à 14:34 - Dernière réponse : cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention
- 20 mars 2006 à 08:51
Bonjour,

j'ai une application faite sous SharpDevelop 2.0 compilée en .NET 1.1.

Mon application n'a pas de bord (this
.FormBorderStyle
= System
.Windows
.Forms
.FormBorderStyle
.None
;)

Donc, directement, je ne peux la déplacer. Alors je me sert de mouseDown, mouseMove et mouseUp pour faire ça.


private Point mouse_pos
;
bool mouse_is_down = false;
static int minDistBorder = 5; //distance pour coller le bord


private void mouseDown(object sender
, MouseEventArgs e
)
{
mouse_pos = Control.MousePosition;
mouse_is_down = true ;
}


private void mouseUp(object sender
, MouseEventArgs e
)
{
mouse_is_down = false;
}


private void mouseMove(object sender
, MouseEventArgs e
)
{
if (mouse_is_down && !this
.WindowState.Equals(FormWindowState.Maximized)) //j'ai cliqué et je ne suis pas en plein ecran
{
if (e.Button.Equals(MouseButtons.Left))//j'ai cliqué gauche
{
Point current_pos = this
.Location;
if ((current_pos.X + (Control.MousePosition.X - mouse_pos.X)) < minDistBorder) //je serais trop pret du bord gauche
{
current_pos.X = 0;) //je me colle
}
else
{
current_pos.X = current_pos.X + (Control.MousePosition.X - mouse_pos.X);) //sinon je m'approche
}
if ((current_pos.Y + (Control.MousePosition.Y - mouse_pos.Y)) < minDistBorder)) //je serais trop pret du haut
{
current_pos.Y = 0;//je me colle
}
else
{
current_pos.Y = current_pos.Y + (Control.MousePosition.Y - mouse_pos.Y);//sinon je m'approche
}
if (Screen.GetWorkingArea(this
).Width - (current_pos.X + (Control.MousePosition.X - mouse_pos.X)) - this
.Width < minDistBorder) //je serais trop pret du bord droit
{
current_pos.X = Screen.GetWorkingArea(this
).Width - this
.Width; //je me colle
}
if (Screen.GetWorkingArea(this
).Height - (current_pos.Y + Control.MousePosition.Y - mouse_pos.Y) - this
.Height < minDistBorder)//je serais trop pret du bas
{
current_pos.Y = Screen. GetWorkingArea (this
).Height - this
.Height;//je me colle
}
this
.Location = current_pos; //j'effectue le deplacement
mouse_pos = Control.MousePosition; //j'enregistre la position de la souris
}
}
}

Sur ma machine de dévellopement, j'ai installé le compact FrameWork 2.0 et 1.1.
Mon application fonctionne très bien, je peux la déplacer facilement.
Je précise que je compile bien en 1.1.
Lorsque je fais dans le programme:
MessageBox. Show (Environment
.Version
.ToString());
j'ai bien "1.1.4322.2032" qui s'affiche sur toutes les machines d'execution (ma machine de developement et les machines cibles).
Sur les machines cibles (qui n'ont que le 1.1 et je ne veux pas les passer en 2.0) ca ne se déplace que de quelques pixel puis ca n'avance plus. Donc ce n'est pas pratique ...

Sur une des machines cibles, j'ai installer le framework 2.0 et là miracle, ca fonctionne bien sur cette machine. Pkoi, aucune idée.

J'ai continué ma recherche de la solution en faisant un deplacement plus direct, sans chercher à coller les bord.
Ca donne dans le mouseMove du clic gauche:


Point current_pos = movePictureBox.Location
;
current_pos.X += Control.MousePosition.X - mouse_pos.X;

current_pos.Y += Control.MousePosition.Y - mouse_pos.Y;

movePictureBox.Location = current_pos
;

Miracle ça fonctionne avec toutes les machines.
J'en déduis que c'est Screen.GetWorkingArea(this
) qui me fait délirer l'application.

Avez vous rencontrez ce genre de probleme?
Avez vous une explication? une solution?

f.colo
Afficher la suite 

Votre réponse

19 réponses

Meilleure réponse
sebmafate 4947 Messages postés lundi 17 février 2003Date d'inscription 14 février 2014 Dernière intervention - 13 mars 2006 à 14:41
3
Merci
la solution est plutot d'intercepter le message WM_NCHITTEST dans WndProc

http://www.csharpfr.com/infomsg/DEPLACER-FENETRE-SANS-BARRE-TITRE_548456.aspx


Sébastien FERRAND (
blog)
[Microsoft MVP Visual C#]

Merci sebmafate 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de sebmafate
Meilleure réponse
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 13 mars 2006 à 17:08
3
Merci
Y'a une astuce qui peut marcher mais ça ne va peut être pas te convenir en passant la propriété Enabled de tes PictureBox à false tu devrais pouvoir intercepter le message WM_NCHITTEST dans la méthode WndProc de ta forme ( comme l'exemple au-dessus ), mais tes PictureBox ne vont plus répondre au clique droit :/

Merci Lutinore 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de Lutinore
Meilleure réponse
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 14 mars 2006 à 11:53
3
Merci
Je t'ai trouvé encore une autre solution, elle est pas de moi, elle est pas super élégante mais elle va très bien pour ce que tu veux faire : )

Plus besoin de WM_NCHITTEST, plus besoin de modifier la propriété Enabled, suffit juste que tes PictureBox dérivent de cette classe :

public class MyPictureBox : PictureBox
{
[ DllImport( "User32.dll" ) ]
private static extern IntPtr SendMessage( IntPtr hWnd, uint msg, UIntPtr wParam, IntPtr lParam );


[ DllImport( "User32.dll" ) ]
private static extern bool ReleaseCapture( );


private const int WM_SYSCOMMAND = 0x0112;


protected override void OnMouseDown( MouseEventArgs e )
{
base.OnMouseDown( e );


if ( e.Button == MouseButtons.Left )
{
ReleaseCapture( );
SendMessage( this.Parent.Handle, WM_SYSCOMMAND, ( UIntPtr )0xF012, IntPtr.Zero );
}
}
}

Merci Lutinore 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de Lutinore
Meilleure réponse
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 14 mars 2006 à 15:44
3
Merci
Plutôt que de reprendre ton premier code je me suis amusé à refaire toute l'application, j'ai testé uniquement en .NET 2.0.

public partial class Form1 : Form
{
private const int WM_MOVING = 0x0216;
private MyPictureBox pb1, pb2, pb3;


public Form1( )
{
InitializeComponent( );


pb1 = new MyPictureBox( );
pb1.Dock = DockStyle.Left;
pb1.BackColor = Color.Aqua;


pb2 = new MyPictureBox( );
pb2.Dock = DockStyle.Fill;
pb2.BackColor = Color.Aquamarine;


pb3 = new MyPictureBox( );
pb3.Dock = DockStyle.Right;
pb3.BackColor = Color.Azure;


this.FormBorderStyle = FormBorderStyle.None;
this.Controls.AddRange( new Control[ ] { pb1, pb2, pb3 } );
}


struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}


protected override void WndProc( ref Message m )
{
if ( m.Msg == WM_MOVING )
{
Rectangle bounds;


unsafe
{
RECT* p = ( RECT* )m.LParam;
bounds = Rectangle.FromLTRB( p->left, p->top, p->right, p->bottom );

Rectangle area = Screen.PrimaryScreen.WorkingArea;
//area.Inflate( -50, -50 ); // Bordure de 50 pixels.

if ( !area.Contains( bounds ) )
{
p->left = this.Left;
p->top = this.Top;
p->right = this.Right;
p->bottom = this.Bottom;
}
}
}


base.WndProc( ref m );
}
}


public class MyPictureBox : PictureBox
{
[ DllImport( "User32.dll" ) ]
private static extern IntPtr SendMessage( IntPtr hWnd, uint msg, UIntPtr wParam, IntPtr lParam );


[ DllImport( "User32.dll" ) ]
private static extern bool ReleaseCapture( );


private const int WM_SYSCOMMAND = 0x0112;


protected override void OnMouseDown( MouseEventArgs e )
{
base.OnMouseDown( e );


if ( e.Button MouseButtons.Left && e.Clicks 1 ) // DoubleClick OK.
{
ReleaseCapture( );
SendMessage( this.Parent.Handle, WM_SYSCOMMAND, ( UIntPtr )0xF012, IntPtr.Zero );
}
}
}

Merci Lutinore 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de Lutinore
Meilleure réponse
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 19 mars 2006 à 03:37
3
Merci
J'ai repris ta première idée pour faire quelque chose de plus simple, comme ça on aura montré toutes les possibilités dans ce topic ; )

// Net 2.0

public partial class Form1 : Form
{
private PictureBox pb1, pb2, pb3;
private Point position;


public Form1( )
{
InitializeComponent( );


pb1 = new PictureBox( );
pb1.Dock = DockStyle.Left;
pb1.BackColor = Color.Aqua;
pb1.MouseDown += Control_MouseDown;
pb1.MouseMove += Control_MouseMove;


pb2 = new PictureBox( );
pb2.Dock = DockStyle.Fill;
pb2.BackColor = Color.Aquamarine;
pb2.MouseDown += Control_MouseDown;
pb2.MouseMove += Control_MouseMove;


pb3 = new PictureBox( );
pb3.Dock = DockStyle.Right;
pb3.BackColor = Color.Azure;
pb3.MouseDown += Control_MouseDown;
pb3.MouseMove += Control_MouseMove;


this.FormBorderStyle = FormBorderStyle.None;
this.Controls.AddRange( new Control[ ] { pb1, pb2, pb3 } );
}


private void Control_MouseDown( object sd, MouseEventArgs e )
{
if ( e.Button == MouseButtons.Left )
{
position = this.PointToClient( Control.MousePosition );
}
}


private void Control_MouseMove( object sd, MouseEventArgs e )
{
if ( e.Button == MouseButtons.Left )
{
Point pos = this.PointToClient( Control.MousePosition );
int x = this.Left + ( pos.X - position.X );
int y = this.Top + ( pos.Y - position.Y );
Rectangle bounds = new Rectangle( x, y, this.Width, this.Height );

Rectangle area = Screen.PrimaryScreen.WorkingArea;
//area.Inflate( -50, -50 ); // Bordure de 50 pixels.

if ( area.Contains( bounds ) )
{
this.Bounds = bounds;
}
}
}
}

Merci Lutinore 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de Lutinore
cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention - 13 mars 2006 à 14:58
0
Merci
J'avais déja vu ce lien mais je n'ai pas sus l'exploiter.

------------------------
Posté par : Lutinore:
Salut, voilà comment on peut déplacer une forme sans bordure, il s'agit de mentir à Windows et lui dire que le curseur est sur la barre de titre alors qu'il est dans l'air client:


private
const
int WM_NCHITTEST = 0x0084;

private
const
int HTCLIENT = 1;

private
const
int HTCAPTION = 2;

protected
override
void WndProc(
ref
Message m )
{

base.WndProc(
ref m );

if ( m.Msg == WM_NCHITTEST )
{

if ( m.Result == (
IntPtr )HTCLIENT )
{
m.Result = (
IntPtr )HTCAPTION;
}
}
}

------------------------
J'ai copier la fonction et les variables pour les coller dans mon application.
J'ai modifier mon initilizeComponent pour ne plus appeler mouseUp, mouseDown et mouseMove.
Ca compile mais ca ne se déplace pas du tout cette fois.
Je pense donc ne pas savoir me servir de WndProc() ...
Serais tu m'expliquer?

f.colo
Commenter la réponse de cs_fcolo
sebmafate 4947 Messages postés lundi 17 février 2003Date d'inscription 14 février 2014 Dernière intervention - 13 mars 2006 à 15:05
0
Merci
normalement, il suffit de coller ce bout de code dans ton formulaire pour que ca fonctionne...


Sébastien FERRAND (
blog)
[Microsoft MVP Visual C#]
Commenter la réponse de sebmafate
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 13 mars 2006 à 15:07
0
Merci
Salut, vi je ne vois pas pourquoi ça ne fonctionnerait pas, tu peux voir un exemple >ici< ou j'utilise cette fonction.
Commenter la réponse de Lutinore
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 13 mars 2006 à 15:22
0
Merci
Peut être tu as un contrôle qui remplit completement la zone cliente..
Commenter la réponse de Lutinore
cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention - 13 mars 2006 à 15:33
0
Merci
OK, ca fonctionne sur une form normale mais pas avec mon programme.
En fait je vais expliquer un peu plus mon programme :)
Pour ceux qui suivent un peu mes questions sur ce forum (on sait jamais que j'ai un fan club ici :D), vous savez que je réalise une application pour visualiser des caméras IP de type Axis.
La visualisation en elle meme est assez simple, récupération de l'image en cours, insertion dans une pictureBox et on boucle.
Maintenant, autour de ca, je souhaite faire un truc jolie.
Mon application consiste à visualiser les 3 caméras de mon entreprise (je suis stagiaire au fait).
Le visuel de ma application est une form sans bord, dans laquelle 3 pictureBox sont collées les unes a cotés des autres de même hauteur. Ma form colle les pictureBox.
Ca ressemble donc à un large rectangle.
Je souhaite pouvoir faire tout bouger (les pictureBox restents collées entre elles) toutes l'application avec un drag&drop clic gauche.
Puis change l'ordre des pictureBox avec un drag&drop clic droit. Durant ce drag&and drop je crée une nouvelle pictureBox contenant l'image courante de la pictureBox à déplacer. Ca fonctionne bien.
Je travaillais au debut avec VS2005 sous .NET 2.0. Les PCs sur lesquels tournent l'application ont le .NET 1.1, donc à chaque fois install du 2.0, assez lourd ...
Donc j'ai voulu passer en 1.1 pour que ce soit plus facile au deploiment.
Donc me voilà avec SharpDevelop et compilation en 1.1.
Galère de mise à niveau du programme mais c'est bon, j'y suis arrivé.
Je me retrouve maintenant avec le problème cité en premier message.

L'utilisation de WndProc ne semble pas etre appelé car je clique sur une pictureBox (vu que je peux pas cliquer sur ma form qui colle les pictureBox).

EN faisant un this.refresh(), ca va mieux mais comme il repaint tous les éléments j'ai du retard sur ma souris et c'est assez génant.

Voila où j'en suis, si vous avec des questions ou des solutions :)

f.colo
Commenter la réponse de cs_fcolo
cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention - 13 mars 2006 à 15:52
0
Merci
Donc oui Lutinore, j'ai mes controle ( 3 pictureBox) qui remplissent toute la zone cliente.

f.colo
Commenter la réponse de cs_fcolo
sebmafate 4947 Messages postés lundi 17 février 2003Date d'inscription 14 février 2014 Dernière intervention - 13 mars 2006 à 15:56
0
Merci
tu devrais regarder ce post de not'cher ami Coq : http://blogs.developpeur.org/coq/archive/2006/01/06/16323.aspx

regarde pour l'adapter à ta situation.


Sébastien FERRAND (
blog)
[Microsoft MVP Visual C#]
Commenter la réponse de sebmafate
cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention - 13 mars 2006 à 16:32
0
Merci
Je patoge dans la semoule là :S dsl !
Donc j'ai essayé de comprendre le post de coq sur son blog.
J'ai pas tout suivis, son code à télécharger n'utilise pas le source fourni, je pense qu'il est là pour nous montrer le probleme des controle enfant ...
Quand à sa classe, ca semble bien, mais je ne comprends pas, dsl.

Pour tester, j'ai betement copier sa classe dans mon source.
Dans mon initializeComponent, j'ai rajouté a la fin:

ContainerLevelMouseEventsMessageFilter clmemf
= new ContainerLevelMouseEventsMessageFilter (this
);

pour espèrer que ça fasse tout seul :) mais non :(
je me suis dis, peut etre ajouter à la main l'evenement de déplacement comme ca:

clmemf
.MouseMove
+ = new System
.Windows
.Forms
.MouseEventHandler(this
.mouseMove
);

mais ca ne fait rien de plus.
Honnetement, je comprends rien à vos override de message windows, je ne sais pas comment vous faite pour trouver tout ca.

Je vais laisser tomber, ca deveint trop compliqué pour mon petit cerveau, il va falloir que je me documente avant de me lancer dans se genre de truc.

Merci encore.

f.colo
Commenter la réponse de cs_fcolo
cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention - 13 mars 2006 à 21:28
0
Merci
Je testerai demain de retour au boulot, mais c'est une bonne solution.
Après je dois avoir quelque part dans un bout de code une fonction qui me dis si la souris est au dessus d'un coposant ou non, dans mon code je faisait déjà le parcours de toutes les pictureBox (je pouvais rajouter et enlever des pictureBox durant l'execution).

Merci encore, je vous tiens au courant demain.

f.colo
Commenter la réponse de cs_fcolo
cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention - 14 mars 2006 à 09:26
0
Merci
Je confirme, en passant la propriété enable de chaque pictureBox à false, je peux déplacer ma form en l'override de WndProc en dupant windows sur la position du curseur.
Me reste plus qu'à remagner mon code pour les menus sur les picture box :)

f.colo
Commenter la réponse de cs_fcolo
cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention - 14 mars 2006 à 13:07
0
Merci
Cette derniere reponse marche super !
Bon, je comprend pas pkoi mais ca fonctionne lol.

Donc, si le pictureBox recois un clic down gauche, il envoie à son parent ( pour moi la form) un message (une commande) OxF012 (alors là je ne sais pas ce que c'est comme commande).
Par contre, le releaseCapture() je ne vois pas ce que c'est ... ca veut peut etre dire qu'il ne tient plus compte du clic.

En tout cas ca fonctionne super. (winXp et win2000)

f.colo
Commenter la réponse de cs_fcolo
cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention - 14 mars 2006 à 13:30
0
Merci
Avec la nouvelle class j'ai plus l'evenement de double clic qui remonte, ni au niveau de la form ni des pictureBox, je pense à case du fameux releaseCapture();

Dans tout ca, j'ai moi même oublié le but principal de ma question :s, surtout que je ne l'avais pas posé, j'étais directement allé au problème.

Ce que je veux faire, c'est de ne pouvoir déplacer ma forme qu'a l'intérieur de l'ecran.
C'est pour celà que, durant le déplacement, je me servais de Screen.GetWorkingArea
(this)
pour délimiter la zone de travail. C'etait cet appel qui merdé.
En faisant directement:

if (e.Button.Equals(MouseButtons.Left))
{
Point current_pos = this .Location;
current_pos.X = current_pos.X + (Control.MousePosition.X - mouse_pos.X);
current_pos.Y = current_pos.Y + (Control.MousePosition.Y - mouse_pos.Y);
this .Location = current_pos;
mouse_pos = Control.MousePosition;
this.Refresh();
}
dans le mouseMove ca fait pareil qu'avec toutes les solutions que vous m'avez donné.

C'est sur, ca m'a permis de mettre un pas dans l'override et ça je vous en remercie encore.
Désolé que vous vous soyez autant pris la tete pour m'aider et en arrivé là ...

Savez vous m'aider un peu plus pour ce problème?

f.colo
Commenter la réponse de cs_fcolo
cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention - 14 mars 2006 à 17:01
0
Merci
Franchement, je reste bleuffé par vos capacités ...
Ton code marche nikel, je ne sais pas comment vous faites pour trouver tout ca.

Par contre, sur les machines où coabitent le .NET 1.1 et 2.0, ca fonctionne super bien.
Mais sur les machines où il n'y a que le .NET 1.1, à chaque fois qu'on touche le bord, on revient à l'endroit initial, pas pratique.
Ca semble être vraiment galère de réaliser ça, je pense que je vais abandonner l'idée de bloquer sur les bord.

En tout cas, heureusement que vous etes là car sinon on n'avancerai pas.

Merci encore, et à bientot pour encore une question sogreunu :)

f.colo
Commenter la réponse de cs_fcolo
cs_fcolo 201 Messages postés mercredi 8 février 2006Date d'inscription 20 février 2007 Dernière intervention - 20 mars 2006 à 08:51
0
Merci
Merci pour ce dernier code,

j'ai modifier un peu pour le passer en .NET1.1 et ca fonctionne également.
J'ai commenté quelques ligne qui ne sont pas prises en .NET 1.1 et rajouté des choses.
Je vais donc pouvoir me repencher dessus pour faire un truc bien pour mon application, merci encore.

f.colo

using System.Collections;
//Application.SetCompatibleTextRenderingDefault(false);


/*protected override void Dispose(bool disposing)
{
if (disposing) {
if (components != null) {
components.Dispose();
}
}
base.Dispose(disposing);
}*/


//this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;


pb1
.MouseDown
+= new MouseEventHandler (Control_MouseDown
);
pb1
.MouseMove
+ = new MouseEventHandler(Control_MouseMove
);
Commenter la réponse de cs_fcolo

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.