Toon posts:

[C#.NET] Shapes resizen, rekening houden multiple selections

Pagina: 1
Acties:

  • NickThissen
  • Registratie: november 2007
  • Laatst online: 22-09 09:49
Hey,

Ik heb een class Shape met properties als Bounds (Rectangle), Location (Point) en Size (Size) (komen rechtstreeks uit Bounds) en een methode Draw.
Dit stelt een vorm voor, zeg een rechthoek, driehoek, cirkel, etc. De vorm wordt met de Draw methode op het scherm getekend, en er worden, als de vorm geselecteerd is, ook 'grab handles' getekend zoals in de Visual Studio form designer. Met deze grab handles kan de gebruiker de shape verplaatsen en ook resizen.

Een tijd geleden had ik hier een vraag gepost over het resizen van de shapes.
Dit hele verhaal is niet veranderd en kan in het oude topic nog gelezen worden. Alles tot de eerste code samples is nog relevant, dat daarna is het probleem wat ondertussen is opgelost.
\[VB.NET] Shapes resizen, rekening houden met minimum size?
Dit probleem is dus opgelost, ik kan de shapes nu mooi resizen.


Maar nu heb ik het volgende probleem: het moet mogelijk zijn om meerdere shapes tegenlijk te selecteren, en ze moeten dus ook tegenlijk worden verplaatst of resized. Nu probeer ik zo dicht mogelijk bij de implementatie van Visual Studio te blijven, en men kan dus net zoals in Visual Studio meerdere shapes selecteren, maar er is altijd 1 'hoofd' selectie (dat zie je aan het verschil in grab handles). Alle uitlijning (snapping met andere shapes en de rand bijvoorbeeld) wordt op deze hoofd shape gedaan.


Het tegenlijkertijd verplaatsen heb ik al uitgewerkt. Dat klinkt triviaal maar ik moest ook rekening houden met snapping enzo (als de hoofd selectie aan het snappen is moeten de andere natuurlijk ook niet bewegen). Nu ben ik al een hele tijd met het resizen bezig, maar het wil weer niet lukken...

Het resizen van een enkele shape is heel gemakkelijk met de Resize method. Deze accepteert een 'HitStatus' (dit bevat de informatie over aan welke kant de shape aan het resizen is, bijvoorbeeld van linksonder of van rechtsboven), en de positie van de muis relatief t.o.v. het 'canvas'.

Zo kan in een MouseMove methode bijvoorbeeld gewoon dit aangeroepen worden:
C#:
1
this.SelectedShape.Resize(hitStatus, e.X, e.Y);

waarbij 'this' de Canvas is en hitStatus ergens anders bepaald wordt.

Nu heb ik dus nog meer selecties naast deze hoofd selectie, en de makkelijkste manier om die ook te laten resizen leek mij om 'simpelweg' de muislocatie (e.X, e.Y) te vertalen naar de overige shapes.

Ik deed dit eerst door simpelweg het punt (e.X, e.Y) relatief t.o.v. de hoofd shape te nemen (shape.Location aftrekken van e.Location), en daarna dit punt terug te verplaatsen naar de andere shape (optellen). In code:
code:
1
2
3
4
5
6
7
8
this.SelectedShape.Resize(hitStatus, e.X, e.Y);

for (int i = 1; i < this.SelectedShapes.Count; i++)
{
    var shape = this.SelectedShapes[i];
    var relativePoint = shape.Location.Add( e.Location.Subtract( this.SelectedShape.Location ) );
    shape.Resize(hitStatus, relativePoint.X, relativePoint.Y);
}

NB: this.SelectedShape == this.SelectedShapes[0], vandaar de loop beginnen vanaf 1 (de hoofd shape
En Add en Subtract zijn extension methods die voor de hand liggen (p1.X + p2.X, p1.Y + p2.Y).

Dit werkt, maar alleen als de shapes precies even groot zijn!
Zodra een van de andere shapes bijvoorbeeld groter is, dan ligt het getransleerde punt niet meer op de rand van de shape en gaat het resizen helemaal mis.

Dus, ik moet het punt niet alleen transleren, maar ook 'schalen' naar de grootte van de andere shape.
Ik heb dit met een tekening geprobeerd duidelijk te maken:

Het rode punt links is de muislocatie. Ik ben dus shape1 aan het resizen. De muislocatie wordt getransleerd naar het doorzichtige rode punt rechts, op shape 2. Dit is natuurlijk niet goed! Hij moet ongeveer bij het groene punt liggen.

Om dit voor elkaar te krijgen dacht ik dat ik niet het exacte punt (e.X, e.Y) moet gebruiken, maar de relatieve waarden, relatief t.o.v. de grootte van de hoofd shape.
Dat wil zeggen: de x waarde delen door de breedte van de hoofd shape (dit wordt dus iets tussen 0.0 en 1.0), en dan vermenigvuldigen met de breedte van de andere shape. Eveneens voor de y waarde, maar dan met de hoogte.

Mijn code nu is als volgt:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
                        var mainShapeBounds = this.SelectedShape.Bounds;

                        // 1. Resize main selected shape
                        this.SelectedShape.Resize(hitStatus, e.X, e.Y);

                        // 2. Resize remaining selected shapes
                        for (var i = 1; i < this.SelectedShapes.Count; i++)
                        {
                            var shape = this.SelectedShapes[i];
                            var currentShapeBounds = shape.Bounds;

                            // 2.1. Determine relative location of point in main shape
                            var relativePoint = e.Location.Subtract(this.SelectedShape.Location);
                            var relativePointF = new PointF(relativePoint.X / (float) mainShapeBounds.Width,
                                                            relativePoint.Y / (float) mainShapeBounds.Height);

                            // 2.2 Determine point relative to other shape
                            relativePointF = new PointF(relativePointF.X * currentShapeBounds.Width + shape.Location.X,
                                                        relativePointF.Y * currentShapeBounds.Height + shape.Location.Y);

                            shape.Resize(hitStatus, (int) relativePointF.X, (int) relativePointF.Y);


Ik wist zeker dat dit zou werken! Maar helaas... Er gaat nog steeds iets mis, maar dit keer kom ik er niet achter wat...

Wat er nu gebeurt is lastig uit te leggen, maar het komt erop neer dat de andere shapes langzaam de grootte van de hoofd shape overnemen. Dat gaat niet meteen, maar als ik mijn muis beweeg (maakt niet uit welke richting) dan resizen de shapes beetje bij beetje totdat ze even groot zijn als de hoofd shape. En op dat moment resizen ze wel weer gewoon goed, zoals in mijn eerste methode.

Ik kom er even niet meer uit... Ik snap dat dit een hele hoop informatie is zonder dat jullie eigenlijk weten wat er aan de hand is, maar als iemand toch ziet wat er mis gaat dan hoor ik dat graag! Een extra paar ogen / hersenen komt vaak een heel eind :P


EDIT
Ik heb mijn project even gecompileerd en geupload:
http://www.megaupload.com/?d=3O711QJP
Met .NET Framework 3.5 of hoger zou je dit moeten kunnen draaien, en dan kun je zelf even kijken wat er precies gebeurt als je meerdere shapes selecteert (ctrl inhouden) en daarna resized. Als een shape een andere grootte heeft gaat het compleet mis.


Bedankt!

Mijn iRacing profiel


  • RobIII
  • Registratie: december 2001
  • Nu online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

Wat je wil is gewoon het verschil in waardes van de originele grootte t.o.v. de resized grootte (de 'delta' zeg maar) in hoogte/breedte van de hoofdselectie loslaten op de andere geselecteerde elementen. Als het hoofdelement 35px breder en 81px hoger gemaakt wordt moet dit ook met de childelementen gebeuren. Lijkt me niet zo heel moeilijk, toch? Enige wat je dan nog moet weten is vanuit welke hoek dit gebeurt zodat de "tegenoverliggende" hoek dus als "anchor" gebruikt wordt en het subselectie dus aan de goede kant groeit (of krimpt).

[Voor 8% gewijzigd door RobIII op 06-10-2010 22:04. Reden: Typo :X % moet natuurlijk px zijn :X]

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

Roses are red Violets are blue, Unexpected ‘{‘ on line 32.

Over mij


  • NickThissen
  • Registratie: november 2007
  • Laatst online: 22-09 09:49
Nou daar heb ik dus over nagedacht, maar ik denk niet dat dat gaat lukken.

Waar dat op neerkomt is namelijk het verschil 'meten' wat de muis bewogen heeft (alleen nu gebruik ik de vergroting van de hoofd shape ipv daadwerkelijk de muis), en dat naar een of andere Resize methode gooien, die dan de shape daarop resized. Dat is precies wat ik deed in de thread waar ik op het begin naar link, namelijk een dx en dy doorgeven en met die waarden de shape vergroten/verkleinen. Maar dan kan ik geen rekening houden met een minimum size. Stel je maakt een shape minder breed met je muis. Zodra je het minimum bereikt kun je de muis natuurlijk wel nog door bewegen (maar de shape doet dan niets). Als je nu de dx en dy gaat gebruiken van de muis, dan zal de shape echter meteen weer gaan vergroten zodra je de muis de andere kant op beweegt, ook al is die nog lang niet voorbij je shape!

Nu doe ik dit dan niet met de muis direct, maar indirect via een andere shape, maar het komt op hetzelfde neer toch? Ik zal het zometeen eens proberen, maar eerlijk gezegd heb ik er weinig hoop op.


EDIT
Hmmm... Het probleem hoe ik het beschrijf is niet op die manier aanwezig, maar er is wel een vergelijkbaar probleem. Stel dat ik twee shapes heb, shape1 en shape2, waarvan shape1 een stuk kleiner is. Als ik ze nu tegenlijk verklein met shape1 als hoofd selectie, (van rechts naar links bijvoorbeeld), dan kan ik dat doen totdat shape1 zijn minimum hit. Daarna beweegt shape1 niet meer, en dus beweegt shape2 ook niet meer. Dat is in de Visual Studio editor niet het geval, shape2 zal dan gewoon door resizen.

Of dit een probleem is.. Tsja, dat vind ik moeilijk te bepalen. Ik ben het gewend zoals in Visual Studio, maar als iemand dat niet kent vind hij dit misschien goed, maar voor mij voelt het heel raar. Ik zoek nog even door, maar als ik niets anders vind dan kan ik dit inderdaad gebruiken.


Mijn "punt" eigenlijk is dat controls in Visual Studio zich gedragen alsof je een aparte muis pointer hebt op elke control, die tegelijk bewegen. Dat is niet het geval in mijn programma op het moment, daar voelt het echt alsof shape2 afhankelijk is van shape1, wat niet het geval zou moeten zijn.

[Voor 34% gewijzigd door NickThissen op 06-10-2010 22:24]

Mijn iRacing profiel



Nintendo Switch (OLED model) Apple iPhone 13 LG G1 Google Pixel 6 Call of Duty: Vanguard Samsung Galaxy S21 5G Apple iPad Pro (2021) 11" Wi-Fi, 8GB ram Nintendo Switch Lite

Tweakers vormt samen met Hardware Info, AutoTrack, Gaspedaal.nl, Nationale Vacaturebank, Intermediair en Independer DPG Online Services B.V.
Alle rechten voorbehouden © 1998 - 2021 Hosting door True

Tweakers maakt gebruik van cookies

Bij het bezoeken van het forum plaatst Tweakers alleen functionele en analytische cookies voor optimalisatie en analyse om de website-ervaring te verbeteren. Op het forum worden geen trackingcookies geplaatst. Voor het bekijken van video's en grafieken van derden vragen we je toestemming, we gebruiken daarvoor externe tooling die mogelijk cookies kunnen plaatsen.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Forum cookie-instellingen

Bekijk de onderstaande instellingen en maak je keuze. Meer informatie vind je in ons cookiebeleid.

Functionele en analytische cookies

Deze cookies helpen de website zijn functies uit te voeren en zijn verplicht. Meer details

janee

    Cookies van derden

    Deze cookies kunnen geplaatst worden door derde partijen via ingesloten content en om de gebruikerservaring van de website te verbeteren. Meer details

    janee