Toon posts:

[C#] Controls flexibel verslepen

Pagina: 1
Acties:
  • 155 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Wij zijn bezig met een panel die we zo aan hebben aangepast dat alle controls die in deze panel staan te verslepen zijn. Echter gaat dit niet al te stabiel, bij het slepen laten de controls een staart achter. Wij hebben een klein voorbeeld projectje gemaakt met daarin alle controls die van toepassing zijn http://clermond.sohosted.com/Voorbeeld.rar
Weet iemand hier toevallig een nette oplossing voor?

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

Invalidate() aanroepen ?

ASSUME makes an ASS out of U and ME


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 17:09

Creepy

Tactical Espionage Splatterer

En wat heb je nu zelf al geprobeerd? Wat ging daar mee mis? Zou je misschien ook de link naar je rar weg willen halen en eventuele relevante code in je startpost willen plaatsen? Dan blijft het topic ook bruikbaar als je in verloop van de tijd je voorbeeld weghaalt :)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Topicstarter
Creepy schreef op dinsdag 18 april 2006 @ 14:20:
En wat heb je nu zelf al geprobeerd? Wat ging daar mee mis? Zou je misschien ook de link naar je rar weg willen halen en eventuele relevante code in je startpost willen plaatsen? Dan blijft het topic ook bruikbaar als je in verloop van de tijd je voorbeeld weghaalt :)
Ik zou niet weten wat ik zou moeten proberen, Invalidaten helpt niet. En ik weet ook niet precies welk stuk code relevant is, wat dat betreft is het hele bestand 'WorkareaPanel.cs' relevant en die bevat 750 regels code en dat lijkt me denk ik iets teveel om te posten.

  • Mastermind
  • Registratie: Februari 2000
  • Laatst online: 17-01 10:57
Kijk eens in de properties van de form en zet DoubleBuffered eens op True?

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

Verwijderd schreef op dinsdag 18 april 2006 @ 14:53:
[...]

Ik zou niet weten wat ik zou moeten proberen, Invalidaten helpt niet. En ik weet ook niet precies welk stuk code relevant is, wat dat betreft is het hele bestand 'WorkareaPanel.cs' relevant en die bevat 750 regels code en dat lijkt me denk ik iets teveel om te posten.
Tijdens je versleep event: Refresh() ?

ASSUME makes an ASS out of U and ME


Verwijderd

Topicstarter
HIGHGuY schreef op dinsdag 18 april 2006 @ 19:42:
[...]


Tijdens je versleep event: Refresh() ?
Hehe, nee dat is helemaal een ramp

  • Mastermind
  • Registratie: Februari 2000
  • Laatst online: 17-01 10:57
Verwijderd schreef op dinsdag 18 april 2006 @ 21:14:
[...]

Hehe, nee dat is helemaal een ramp
Nog maar een keer dan.
C#:
1
this.DoubleBuffered = true;

  • RedBeard
  • Registratie: April 2006
  • Niet online
Ik heb heel even naar je code gekeken
Het probleem is dat je van alle geselecteerde objecten bij elke verplaatsing de positie opnieuw doorrekend. Als je muis dan weer een milimeter verder is begint dit proces opnieuw maar wordt eerst de andere afgerond.
Dus krijg je een vertraging en dus krijg je die staart.

Ik zou denk ik ervoor zorgen dat het mouseevent pas afgehandeld wordt als de muis even stilstaat.
of in ieder geval zorgen dat de verwerking van het oude event stopt op het moment dat het proces weer aangeroepen wordt.

I'm not anti-social, I'm just not user friendly


Verwijderd

Topicstarter
RedBeard schreef op woensdag 19 april 2006 @ 08:45:
Ik heb heel even naar je code gekeken
Het probleem is dat je van alle geselecteerde objecten bij elke verplaatsing de positie opnieuw doorrekend. Als je muis dan weer een milimeter verder is begint dit proces opnieuw maar wordt eerst de andere afgerond.
Dus krijg je een vertraging en dus krijg je die staart.

Ik zou denk ik ervoor zorgen dat het mouseevent pas afgehandeld wordt als de muis even stilstaat.
of in ieder geval zorgen dat de verwerking van het oude event stopt op het moment dat het proces weer aangeroepen wordt.
dit klinkt inderdaad logisch! we gaan het per direct proberen. Bedankt!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Verwijderd schreef op woensdag 19 april 2006 @ 13:42:
[...]

dit klinkt inderdaad logisch! we gaan het per direct proberen. Bedankt!
Zowieso is het misschien aan te raden niet voor alle objecten tijdens het slepen die "snap" te berekenen, maar bijv. alleen voor de linksbovenste of de "actieve / laatst geselecteerde".

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Verwijderd

Topicstarter
RobIII schreef op woensdag 19 april 2006 @ 13:50:
[...]

Zowieso is het misschien aan te raden niet voor alle objecten tijdens het slepen die "snap" te berekenen, maar bijv. alleen voor de linksbovenste of de "actieve / laatst geselecteerde".
Dit is ook niet het geval, de mousemove wordt alleen getriggerd van de actieve (waar op geklikt is)
Er wordt echter wel door elk control heen gelopen om te kijken of hier aan 'gesnapt' moet worden

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Verwijderd schreef op woensdag 19 april 2006 @ 17:15:
[...]

Dit is ook niet het geval, de mousemove wordt alleen getriggerd van de actieve (waar op geklikt is)
Er wordt echter wel door elk control heen gelopen om te kijken of hier aan 'gesnapt' moet worden
Dun kun je zowieso de controls die in de selectie zitten "skippen" omdat ze "lijdend voorwerp" zijn ;)
En zo zijn er nog wel wat optimalisaties te bedenken voor zover ik kan zien.

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Verwijderd

Topicstarter
RedBeard schreef op woensdag 19 april 2006 @ 08:45:
Ik heb heel even naar je code gekeken
Het probleem is dat je van alle geselecteerde objecten bij elke verplaatsing de positie opnieuw doorrekend. Als je muis dan weer een milimeter verder is begint dit proces opnieuw maar wordt eerst de andere afgerond.
Dus krijg je een vertraging en dus krijg je die staart.

Ik zou denk ik ervoor zorgen dat het mouseevent pas afgehandeld wordt als de muis even stilstaat.
of in ieder geval zorgen dat de verwerking van het oude event stopt op het moment dat het proces weer aangeroepen wordt.
Ik heb nu het volgende gedaan

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void Control_MouseMove(object sender, MouseEventArgs e)
{
    //prevent this event from being triggered if the event is still being processed
    if (moving) return;
    
    //tell the system this event is being processed
    moving = true;
    
    [de daadwerkelijke verplaatsingscode]
    
    //get rid of the 'movingtail'
    Application.DoEvents();
    //tell the system this events is finished
    moving = false;
}


En dit is tot nu de beste oplossing wat ik heb kunenn vinden, echter, dit heeft als effect dat wanneer een aantal controls snel worden gesleept en los worden gelaten, hij de laatste aktie niet uitvoert.
Is er niet een manier om ervoor te zorgen dat alle events die nog uitgevoerd moeten worden, verwijderd worden?

[ Voor 19% gewijzigd door Verwijderd op 19-04-2006 17:43 ]


Verwijderd

Topicstarter
RobIII schreef op woensdag 19 april 2006 @ 17:33:
[...]

Dun kun je zowieso de controls die in de selectie zitten "skippen" omdat ze "lijdend voorwerp" zijn ;)
En zo zijn er nog wel wat optimalisaties te bedenken voor zover ik kan zien.
vanzelfsprekend is dit ook al het geval :)
code:
1
2
3
4
5
6
7
//walk through every control in the panel
foreach (Control control in this.Controls)
{
    //dont try to snap to a control we are currently moving
    if (!movingControls.Contains(control))
    {
        ...

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

schrijf aub geen Application.DoEvents() op het einde van een event...

en in dit geval al zéker niet als je daarna moving terug op false zet...

redeneer nou even zelf wat er gebeurt... ;)

ASSUME makes an ASS out of U and ME


Verwijderd

Topicstarter
HIGHGuY schreef op woensdag 19 april 2006 @ 17:58:
schrijf aub geen Application.DoEvents() op het einde van een event...

en in dit geval al zéker niet als je daarna moving terug op false zet...

redeneer nou even zelf wat er gebeurt... ;)
zonder Application.DoEvents() heb ik nog steeds last van de hele 'staart van beweging'

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
En mét de DoEvents gaan je events door elkaar lopen. Kiezen of delen ;)
DoEvents in een event is zowieso altijd een slecht idee IMHO, en eigenlijk is naast GoTo DoEvents gewoon evil :P

Sterker:
Afbeeldingslocatie: http://msdn2.microsoft.com/en-us/library/ms127628.Caution.gif Caution
If a method that handles a user interface (UI) event calls the My.Application.DoEvents method, the method might be re-entered before it finishes. This can happen because the My.Application.DoEvents method processes Windows messages, and Windows messages can raise events.

[ Voor 58% gewijzigd door RobIII op 19-04-2006 19:00 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • RedBeard
  • Registratie: April 2006
  • Niet online
Verwijderd schreef op woensdag 19 april 2006 @ 17:41:
[...]


Ik heb nu het volgende gedaan

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void Control_MouseMove(object sender, MouseEventArgs e)
{
    //prevent this event from being triggered if the event is still being processed
    if (moving) return;
    
    //tell the system this event is being processed
    moving = true;
    
    [de daadwerkelijke verplaatsingscode]
    
    //get rid of the 'movingtail'
    Application.DoEvents();
    //tell the system this events is finished
    moving = false;
}


En dit is tot nu de beste oplossing wat ik heb kunenn vinden, echter, dit heeft als effect dat wanneer een aantal controls snel worden gesleept en los worden gelaten, hij de laatste aktie niet uitvoert.
Is er niet een manier om ervoor te zorgen dat alle events die nog uitgevoerd moeten worden, verwijderd worden?
Ik zal morgen even rustig kijken wat ik zou doen. Daarvoor moet ik de code iets beter bekijken.

I'm not anti-social, I'm just not user friendly


  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

ik heb 30sec in je code gekeken en de uitroep was: OMFG

wat denk je van deze eenvoudige pseudocode:
code:
1
2
3
4
5
6
7
8
9
10
gebruik 4 gesorteerde lijsten voor links boven rechts onder
overloop alle controls inclusief eigen panel waaraan gesnapt kan worden
    voeg Left, Right, Bottom, Top toe aan de respectieve lijstjes

// 4x in de volgorde die je zelf wil:
zoek het dichtstbijzijnde getal voor de eigenschap(L/R/T/B) in de lijst
   als dicht genoeg:
        snap en break

Invalidate

deze is O(n + lg n) met n het aantal controls

ASSUME makes an ASS out of U and ME


Verwijderd

Topicstarter
HIGHGuY schreef op woensdag 19 april 2006 @ 19:17:
ik heb 30sec in je code gekeken en de uitroep was: OMFG

wat denk je van deze eenvoudige pseudocode:
code:
1
2
3
4
5
6
7
8
9
10
gebruik 4 gesorteerde lijsten voor links boven rechts onder
overloop alle controls inclusief eigen panel waaraan gesnapt kan worden
    voeg Left, Right, Bottom, Top toe aan de respectieve lijstjes

// 4x in de volgorde die je zelf wil:
zoek het dichtstbijzijnde getal voor de eigenschap(L/R/T/B) in de lijst
   als dicht genoeg:
        snap en break

Invalidate

deze is O(n + lg n) met n het aantal controls
Voor zover ik weet scheelt dat niets qua performance en minimaal aan code, of zie ik dit nou verkeerd? :/

Verwijderd

Topicstarter
RobIII schreef op woensdag 19 april 2006 @ 18:58:
En mét de DoEvents gaan je events door elkaar lopen. Kiezen of delen ;)
DoEvents in een event is zowieso altijd een slecht idee IMHO, en eigenlijk is naast GoTo DoEvents gewoon evil :P

Sterker:

[...]
Ben zelf ook niet tevreden over de DoEvents en inderdaad, zonder
code:
1
if (moving) return;
gingen inderdaad alle events door elkaar lopen.
Maar tot nu werkt DoEvents + bovenstaande code het beste :|

  • RedBeard
  • Registratie: April 2006
  • Niet online
OK ik heb een werkende optie.
let niet op de code want het is niet heel netjes.

code:
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
private void Control_MouseMove(object sender, MouseEventArgs e)
        {
            Graphics graph = this.CreateGraphics();
            graph.Clear(this.BackColor);
            if (controlMoving && movingControls.MainControl != null && movingControls.MainControl == (Control)sender)
            {
///teken een rechthoek als indicatie voor de te verplaatsen objecten
                Rectangle rect = new Rectangle(e.X + movingControls.MainControl.Location.X - currentcontrolOffsetY, e.Y + movingControls.MainControl.Location.Y - currentcontrolOffsetY, 50, 50);
                
                Pen p = new Pen(Color.Gray);
                p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                graph.DrawRectangle(p,rect);
                
            }
            
        }

        private void Control_MouseUp(object sender, MouseEventArgs e)
        {
            if (selectableControls && e.Button != MouseButtons.Right)
            {
                //hier verplatsen we pas echt
                Graphics graph = this.CreateGraphics();
                graph.Clear(this.BackColor);
                MoveControl(sender, e); 
                //if the mouse button was released, and the control has not been moved the control needs to be selected
              
///jouw eigen code
            }

            //tell the system, no control is being moved at the time
            controlMoving = false;
        }
        private void MoveControl(object sender,MouseEventArgs e)
        {
            ///je eigen moving verhaal
        }


Ik laat dus een soort placeholder teken ipv continu de controls te slepen.
Om het netter te maken kun je ervoor zorgen dat de placeholder exact de form en maten heeft van de geselecteerd objecten.

Hoop dat dit je probleem oplost

I'm not anti-social, I'm just not user friendly


Verwijderd

Topicstarter
Ik had in het begin inderdaad ook na zitten denken om het als een plaatje te verplaatsen, maar dacht dat er misschien wel een makkelijkere manier was, of dat ik iets doms over het hoofd had gezien. Maar nu heb ik een een plaatje gemaakt van de geselecteerde controls en versleep het dus als een plaatje.
Nu heb ik het zo
C#:
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
    //Deze geeft het plaatje terug van de geselecteerde controls (onderdeel van 'movingControls')
    public Bitmap GetBitmap()
    {
        Bitmap bm = new Bitmap(this.Width, this.Height);

        int left = this.Left;
        int top = this.Top;

        foreach (WorkAreaControl c in controls)
        {
            c.Control.DrawToBitmap(bm, new Rectangle(c.Left - left, c.Top - top, c.Control.Width, c.Control.Height));
        }

        return bm;
    }
///////////////////
        private void Control_MouseDown(object sender, MouseEventArgs e)
        {
            if (moveableControls || selectableControls)
            {
                //clear the movingcontrols
                movingControls.Clear();

                //set controlmoved to false
                controlMoved = false;

                if (moveableControls)
                {
                    //if control is being clicked, let the system know
                    controlMoving = true;

                    //if the control where is clicked on is selected
                    if (selectedControls.Contains((Control)sender))
                    {
                        //we let the system know we are moving all selected controls
                        movingControls.Add((Control[])selectedControls.ToArray(typeof(Control)));
                    }
                    else
                    {
                        //otherwise we only move this control
                        movingControls.Add((Control)sender);
                    }

                    //set the main control to the control where is being click on
                    movingControls.SetMaincontrol((Control)sender);

                    //bring the control to the front
                    movingControls.MainControl.BringToFront();

                    //set the offset off the click on the control
                    currentcontrolOffsetX = e.X;
                    currentcontrolOffsetY = e.Y;

                    //now create the bitmap of the selected area (shown when moving)
                    movingControlsBitmap = movingControls.GetBitmap();
                }
            }
        }

        private void Control_MouseMove(object sender, MouseEventArgs e)
        {
            //movingControlsGraphic = Graphics.FromImage(b);
            if (controlMoving && movingControls.MainControl != null && 
                movingControls.MainControl == (Control)sender)
            {
                if (!controlMoved)
                {
                    controlMoved = true;
                    movingControls.Hide();
                }

                Graphics graph = this.CreateGraphics();
                graph.Clear(this.BackColor);

                graph.DrawImage(movingControlsBitmap, 
                    e.X + movingControls.Left - currentcontrolOffsetX, 
                    e.Y + movingControls.Top - currentcontrolOffsetY);
            }

        }

        private void Control_MouseUp(object sender, MouseEventArgs e)
        {
            if (selectableControls && e.Button != MouseButtons.Right)
            {
                //hier verplatsen we pas echt
                Graphics graph = this.CreateGraphics();
                graph.Clear(this.BackColor);
                MoveControl(sender, e);
                movingControls.Show();
                //if the mouse button was released, and the control has not been moved the control needs to be selected

                ///jouw eigen code
            }

            //tell the system, no control is being moved at the time
            controlMoving = false;
        }


Dit werkt perfect op een irritante flikkering bij het verslepen na (doublebuffer heb ik aan staan). Iemand een eenvoudige manier om dit te voorkomen?

[ Voor 13% gewijzigd door Verwijderd op 20-04-2006 15:09 ]


  • RedBeard
  • Registratie: April 2006
  • Niet online
Lees dit artikel even door
en eventueel deze

I'm not anti-social, I'm just not user friendly


Verwijderd

Topicstarter
RedBeard bedankt voot de 2 links om het knipperen tegen te gaan. Het slepen gaat nu soepel zonder dat het plaatje knippert. Maar nu heb ik weer een ander probleem. Bij het mouse up event vervang ik het plaatje dus weer voor de daadwerkelijke controls. Maar op dit moment worden alle controls opnieuw getekend en dit is zeer duidelijk te zien. Eerst worden de Controls gewoon getekend en dan komt pas de selectie eroverheen.Wat kan ik hier tegen doen ?

http://clermond.sohosted.com/slepen.rar

  • RedBeard
  • Registratie: April 2006
  • Niet online
Je kan eventueel even kijken naar de suspendlayout

wat in ieder geval zal helpen is eerst bitmap op null zetten en dan de controls tekenen

[ Voor 48% gewijzigd door RedBeard op 24-04-2006 10:08 ]

I'm not anti-social, I'm just not user friendly


Verwijderd

Topicstarter
RedBeard schreef op maandag 24 april 2006 @ 10:07:
Je kan eventueel even kijken naar de suspendlayout

wat in ieder geval zal helpen is eerst bitmap op null zetten en dan de controls tekenen
Hartstikke bedankt voor alles! nu werkt het inderdaad goed!
_/-\o_
Pagina: 1