juiste manier van programmeren C#

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
Ik ben voor school bezig met het leren van C#, maar ondanks het internet en de mij verstrekte informatie kom ik nog niet helemaal uit het volgende:

Ik probeer een soort vector tekenprogramma te schrijven, hierin kan vooralsnog alleen nog maar een lijn worden getrokken. Deze lijn kan worden getekend door op een punt te klikken (het beginpunt), en vervolgens op een ander punt (het eindpunt). Nadat er op het eerste punt is geklikt verschijnt er ook een als het ware tijdelijke lijn, tussen het beginpunt en het punt waar de muis cursor zich op dat moment bevind.

In princiepe heb ik bovenstaande perfect werkend gekregen, maar ik weet niet of mijn aanpak juist is. Ik heb namelijk een een classe genaamd "tekenenalgemeen" gemaakt, waarvan nu alleen nog maar de tekenklasse voor de lijn erft, genaamd "tekenlijn". Maar later gaan hier ook andere klassen zoals "tekenvierkant" "tekencirkel" etc van erven. In deze tekenenalgemeen staan een aantal protected fields, die van toepassing zijn op alle ervende klassen (nu dus alleen nog maar tekenlijn). Volgens mij was dit allemaal nog de bedoeling. Maar nu komt mijn probleem: Er moeten uiteraard meerdere lijnen worden getekend, al deze lijnen moeten op de één of andere manier worden opgeslagen in een list, zodat ze bij bv minimaliseren en weer openen van het venster opnieuw kunnen worden getekend. Wat kan ik dan het beste opslaan in deze list? Want het tekenen van een lijn wordt nu gedaan door twee keer een functie in de tekenlijn klasse aan te roepen, die dan zelf bijhoud of het de eerst klik is (en de doorgegeven locatie het beginpunt is), of de tweede klik is (en de doorgegeven locatie het eindpunt is en de lijn moet worden getekend). Moet ik dan gewoon beide aanroepen van de van de functie in de tekenlijn klasse opslaan in die list, en dan aanroep voor aanroep uit die list weer opnieuw doen? Dit lijkt mij niet de meest handige methode, aangezien het later ook mogenlijk moet worden lijnen te verwijderen, en dan moet je dus uit gaan zoeken welke twee aanroepen die lijn tekenden, om die vervolgens uit de list te verwijderen...

Ik weet verder ook niet of dit de beste manier van bijhouden welke klik het is (dus de eerste of tweede)...

Als er verder nog dingen niet kloppen aan mijn manier van programmeren hoor ik dat natuurlijk ook graag.

Acties:
  • 0 Henk 'm!

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Ik zou zeggen dat je een klasse Lijn maakt (of beter nog, Line) en die een aantal eigenschappen en methoden geeft. TekenLijn is namelijk geen logische klasse, maar Teken (Draw) is een methode die op een Lijn uitgevoerd kan worden :)

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
ik snap je uitleg nog niet helemaal, ik heb nu de volgende structuur:

- Tekenenalgemeen
- tweepunts objecten
-tekenlijn
-tekenrechthoek
- meerpuntsobjecten
- tekenlijn
- etc

In die tekenlijn klasse zit nu dit:
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
38
39
40
41
42
43
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Vector_Tekenprogramma
{
    class TekenLijn : TekenenAlgemeen
    {
        Pen pen;

        public TekenLijn(Graphics graphics)
        {
            pen = new Pen(Color.Black);
            g = graphics;
        }

        public void tekenlijn(Point locatie)
        {
            if (klikkenteller == 0) // als het de eerste klik is slaat hij het beginpunt op, en zet hij de klikkenteller op 1
            {
                beginpunt = locatie;
                klikkenteller = 1;
            }
            else // als het niet de eerste klik is slaat hij het eindpunt op, zet de klikkenteller weer op 0, ent tekend dan de lijn
            {
                eindpunt = locatie;
                klikkenteller = 0;
                g.DrawLine(pen, beginpunt, eindpunt);
            }
        }

        public void tijdelijkelijn(Point tijdelijkeindpunt) // deze methode wist eerst het hele veld, en tekend dan de tijdelijke lijn (deze methode wordt steeds via een mousemove in de interface aangeroepen)
        {
            g.Clear(Color.White);
            g.DrawLine(pen, beginpunt, tijdelijkeindpunt);
        }
    }
}


En in de "tekenenalgemeen" klasse zit nu dit:

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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Vector_Tekenprogramma
{
    class TekenenAlgemeen
    {
        protected Point beginpunt;
        protected Point eindpunt;
        protected int klikkenteller;
        protected Graphics g;

        public TekenenAlgemeen()
        {
        }

        public int Klikkenteller
        {
            get { return klikkenteller;  }
            set {}
        }

    }
}

[ Voor 16% gewijzigd door huub8 op 25-04-2010 17:13 ]


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 15:05

Sebazzz

3dp

Hoewel het natuurlijk subjectief is, zou ik zowieso aanraden om een Engelse benaming aan te houden, je werkt immers met een Engelstalige taal en framework. In het Engels kan je functies en namen ook beter uitdrukken.

En anders kan je beter een Nederlandstalige taal opzoeken, publieke statische leegte TekenLijn() :p

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Normaal gezien maak je de "gedeelde" functionaliteit in 1 klasse. Voor getekende objecten denk je dan aan "kleur" ofzo.
Dan kan je nog virtuale functies hebben, die geimplementeerd worden in de overervende klasse. Voor getekende objecten denk je dan aan een "Teken" methode.

Succes ;)

-niks-


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
zou iemand dan bijvoorbeeld kunnen aangeven wat er i mijn tekenalgemeen klasse bv moet komen? En hoe ik het beste kan zorgen dat er een verschil is tussen de eerste en tweede klik qua resultaat?

Acties:
  • 0 Henk 'm!

  • Alex)
  • Registratie: Juni 2003
  • Laatst online: 21-08 11:20
Wat mij lijkt, is dat je een base class of een interface definieert waarvan alle objecten die je wilt tekenen overerven. Vervolgens sla je in die objecten de bijbehorende informatie op (zoals coördinaten en andere logica), en store je die objecten in een lijst op. Daarna kun je simpelweg itereren over die lijst en op ieder object de Draw-method aanroepen, zodat de objecten opnieuw gaan tekenen.

Voorbeeldje:
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
interface IDrawingBase
{
    void Draw();
}

class Lijn : IDrawingBase
{
    public Point punt1 { get; set; }
    public Point punt2 { get; set; }
    public void Draw() { /* implementatie hier */ }
}

class Zestienhoek : IDrawingBase
{
    public List<Point> punten { get; set; }
    public void Draw() { /* implementatie hier */ }
}

class Main
{
    private List<IDrawingBase> objecten = new List<IDrawingBase>();
    objecten.Add(new Lijn());
    objecten.Add(new Zestienhoek());

    foreach(IDrawingBase tekenObject in objecten)
    {
        tekenObject.Draw();
    }
}


Wat ik hier doe is dat ik verschillende objecten maak. Allemaal implementeren ze een interface, waardoor er methods zijn (Draw) die precies voldoen aan de interface. De rest voeg je zelf toe naargelang je ze nodig hebt in je object. Vervolgens kun je die opslaan in een lijst, en simpelweg .Draw() aanroepen op het object wat erinstaat.

Het object is zelf verantwoordelijk voor wat hij gaat tekenen. Eventueel zou je nog kunnen overwegen om een parameter aan Draw() mee te geven - een Graphics-object waarop getekend moet worden. Als je dat doet kun je namelijk makkelijk je methods hergebruiken. :)

edit: whoa, typ je even een voorbeeldje en staan er meteen een paar replies boven

We are shaping the future


Acties:
  • 0 Henk 'm!

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Ja da's dus niet bepaald OO. Dat komt op meer neer dan "flikker alles wat met één onderwerp te maken heeft in een klasse" zoals veel PHP'ers ook schijnen te denken. Heb je een boek over C# of een boek over OOP gekregen bij het vak waarvoor je dit doet?

Ik zou als ik jou was, en dat is niet lullig bedoeld, eerst even kijken wat OO precies inhoudt. Een kleine hint:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Line : Shape
  {
    private Point StartPoint { public get; set; }
    private Point EndPoint { public get; set; }

    public void SetPoint(Point p)
    {
      if (StartPoint == null)
      {
        StartPoint = p;
      }
      else
      {
        EndPoint = p;
      }
    }

    public override void Draw(Graphics g)
    {
      g.DrawLine ...
    }
  }


En in de Shape-klasse maak je dan een abstracte draw-methode en een Color-attribuut, want die delen alle objecten die hiervan afgeleid zijn. :)

Alex) :(

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
@TS: je naamgeving is helemaal lekker. Dat komt mede door het Nederlands, maar ook door de manier van naamgeven in het algemeen. Al je classes met "Teken" laten beginnen is geen goed idee, daar zijn namespaces voor: omdat je namespace al "Teken" bevat, hoef je die niet te herhalen.

Ook is "(Teken)Algemeen" geen goede naam. Classes representeren "dingen". Een Algemeen is geen ding. Een Shape (Vorm) is wel een ding. Een Line is een ding dat kan erven van Shape.

Je methodes hebben ook niet allemaal goede namen. "tekenlijn" (ik zou eerder drawLine gebruiken: elk woord behalve het eerste begint met een hoofdletter) is op zich wel goed (maar zie ook hieronder), maar "tijdelijkelijn" niet. Methodes (niet: functies) zijn acties, zorg dus altijd dat de naam van een method een werkwoord bevat.

Denk verder na over welk gedrag gemeenschappelijk is. Shapes zouden zichzelf moeten kunnen tekenen. Door het tekenen van een lijn "tekenlijn" en het tekenen van een vierkant "tekenvierkant" haal je het gemeenschappelijke weg. Dit heeft ook te maken met encapsulation (het verbergen van wat de buitenwereld niet hoeft te weten). Een Shape zou kunnen bestaan uit een aantal punten met daartussen lijnen. Een Line bestaat uit twee punten. Een Square uit vier. Als je in Shape een draw() methode maakt die z'n werk kan doen op basis van een lijst met punten (die echter verborgen blijft voor de buitenwereld), dan los je het probleem op één plek op, in plaats van dat je elke keer het wiel opnieuw gaat uitvinden.

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
@ Herko_ter_Horst: bedankt voor je tips, ik zal mijn naamgeving erop aanpassen.

Verder snap ik nog niet helemaal wat codecaster schreef, is dit de methode voor het tekenen van een lijn? En zit er dan in de shape klasse ook een draw methode, die hierdoor overschreven wordt? Zo ja, wanneer wordt deze dan niet overschreven, oftewijl, waar dient deze "orginele" draw methode dan voor? En wanneer maak je gebruikt van deze properties?
Wordt verder setpoint dan via een mouseclick in het formulier aangeroepen?

Ik heb helaas geen boek gekregen, enkel een paar bladzijdes uitleg, maar daar leggen zie alleen het algemene principe uit.

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Functies met dezelfde naam die enkel in case verschillen is ook geen goed idee.
C#:
1
2
public TekenLijn(Graphics graphics) //<- Constructor
public void tekenlijn(Point locatie) //<- Method


Functies met dezelfde naam ongeacht de case zouden hetzelfde moeten doen binnen een class, meestal is het aantal parameters verschilt, dit voorkomt verwarring als de classe als een black box wordt gebruikt.\

De base class implementation van een functie bevat de generieke manier om die functie te gebruiken. In een inherited class overschrijf je een functie om er een meer specifieke implementatie te geven die gebruik maakt van de extra informatie in dat object

[ Voor 23% gewijzigd door NC83 op 25-04-2010 18:11 ]

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
hoe zou de base classe in mijn geval er dan bijvoorbeeld uitzien?

Acties:
  • 0 Henk 'm!

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

huub8 schreef op zondag 25 april 2010 @ 18:00:
@ Herko_ter_Horst: bedankt voor je tips, ik zal mijn naamgeving erop aanpassen.

Verder snap ik nog niet helemaal wat codecaster schreef, is dit de methode voor het tekenen van een lijn? En zit er dan in de shape klasse ook een draw methode, die hierdoor overschreven wordt? Zo ja, wanneer wordt deze dan niet overschreven, oftewijl, waar dient deze "orginele" draw methode dan voor? En wanneer maak je gebruikt van deze properties?
Wordt verder setpoint dan via een mouseclick in het formulier aangeroepen?

Ik heb helaas geen boek gekregen, enkel een paar bladzijdes uitleg, maar daar leggen zie alleen het algemene principe uit.
Er is niet "een" methode om dit te doen, er leiden veel wegen naar Rome :P Zoals Herko_ter_Horst het voorstelt is ook goed, dat Shape dus een lijst met meerdere Points bevat die 'ie via z'n eigen Draw-methode op het scherm tekent. Dan hoef je 'm inderdaad niet per ervende vorm (Line, Square, Rectangle) te implementeren, maar gewoon in één methode lijnen trekken tussen de verschillende punten als dat er meer dan één zijn. Vervolgens regel je per AddPoint inderdaad dat er bij iedere muisklik een punt wordt toegevoegd.

Vervolgens kun je zoals Alex) laat zien alle vormen tekenen door door je collectie te itereren en één voor één de Draw-methode aan te roepen :)
huub8 schreef op zondag 25 april 2010 @ 18:16:
hoe zou de base classe in mijn geval er dan bijvoorbeeld uitzien?
Ga zelf eens redeneren ;)

[ Voor 7% gewijzigd door CodeCaster op 25-04-2010 18:19 ]

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
ik denk alleen dat mijn leraar meer de manier met ervende vorm (Line, Square, Rectangle) kan waarderen, maar ik snap die post van jou nog niet helemaal, wat doet die point classe bv nou precies? En wat bedoel je met g.drawline ... ?

Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

huub8 schreef op zondag 25 april 2010 @ 18:47:
ik denk alleen dat mijn leraar meer de manier met ervende vorm (Line, Square, Rectangle) kan waarderen, maar ik snap die post van jou nog niet helemaal, wat doet die point classe bv nou precies? En wat bedoel je met g.drawline ... ?
Lees de MSDN website met documentatie anders eens, en dan waarschijnlijk System.Drawing namespace. Alles wat jij hier benoemt, bestaat al.

Iets over wielen opnieuw uitvinden...

Als je iets wilt leren, kan je misschien eerst eens afkijken hoe het gedaan is, beter goed gejat dan slecht bedacht...

-niks-


Acties:
  • 0 Henk 'm!

Verwijderd

Ik zou je willen aanraden om toch maar even in het principe van OOP te duiken. Teken eerst een diagram, bedenk de methoden erbij en ga dan programmeren.

Wat opmerkingen:

De klasse TekenAlgemeen slaat twee punten op. Waarom? Een lijn heeft twee punten. TekenAlgemeen (wat dat ook moge zijn) heeft geen twee punten.

Een klasse is in dat geval iets.
Een lijn is iets, een punt is iets. een cirkel is iets. TekenAlgemeen is niets, TekenLijn ook niet.

Wat wil je hebben?
  • Een lijn
  • Een cirkel
  • Een vierkant
Waar bestaat alles uit?
  • Een lijn bestaat uit twee punten.
  • Een cirkel bestaat uit meerdere lijnen (neem ik aan).
  • Een vierkant bestaat uit meerder lijnen.
Welke klassen heb ik dus nodig en waar wijzen ze naartoe?
  • Lijn bestaat uit 2 punten. Coördinaten waarschijnlijk (Int).
  • Vierkant bestaat uit meerdere lijnen (Lijn).
  • Cirkel bestaat uit meerdere lijnen (Lijn).
Begin zo en werk nu de methoden uit. Als je les hebt gehad in het modelleren met UML-diagrammen zou ik het lesboek ook zeker erbij pakken. :)

Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
helaas heb ik dus geen echte les hierover gehad, is slechts een keuzevak dat ik volg, maar moet dit wel zien te snappen.

Verder dacht ik meer aan indelen op het aantal punten wat betreft hoe het wordt getekend, dus ook een cirkel zou kunnen worden getekend door op een punt te klikken (word het middelpunt) en op een tweede punt (wordt een punt op de buitenrand), en een rechhoek door de linker bovenhoek aan te geven en de rechte bovenhoek. Dus dan bestaat eigenlijk alles uit twee punten, die in de klassen dus worden omgevormd tot de figuren toch?

Acties:
  • 0 Henk 'm!

  • qanar
  • Registratie: Februari 2008
  • Laatst online: 21-05-2019
Hoe wil je dan een onregelmatige veelhoek tekenen?

Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
daar kwam in nog niet aan toe, maar ik geloof dat mijn leraar ongeveerd dit schema maakte:

- drawing
* tweepuntsfiguren
  • - lijn
  • - cirkel
  • - rechthoek
* meerpuntsfiguren
  • - veelhoek
  • - andere afwijkende meerpuntsfiguren

[ Voor 10% gewijzigd door huub8 op 25-04-2010 21:02 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Ja dat klopt. De klassen Lijn, Vierkant, Cirkel zouden dan alle 3 hun eigenschappen kunnen erven van een klasse Vorm.

Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
maar wat ik dus niet snap is wat ik nou precies in drawing moet plaatsen, en wat in meerpuntfiguren/tweepuntsfiguren...

(sorry voor de waarschijnlijk zeer domme vragen, maar zelfs met de vele tutorials over OOP snap ik de praktijk in mijn geval nog niet :P)

[ Voor 38% gewijzigd door huub8 op 25-04-2010 21:23 ]


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
In de figuur klasse sla je de data op die de figuur beschrijft, eventueel een deel tekenen gegevens zoals de plek waar he object zich bevindt in de wereld. In de teken functie gebruik je dan deze data om het figuur te tekenen.♦

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
Simpel gezegd heb je één basis object (of een interface, ligt er maar net aan), wat een vorm voorstelt (daarom zou ik die klasse Shape noemen). Deze klasse/interface heeft op z'n minst een Draw methode, die de vorm dus zal tekenen zodra die methode aangeroepen wordt.

Daarna kun je specifiekere vormen maken, bijvoorbeeld een klasse Line, Rectangle, Circle, die overerven van Shape. Omdat ze overerven van Shape moeten ze persé de Draw methode implementeren. Natuurlijk is de implementatie van de Draw methode voor een Line anders dan voor een Circle.
Naast de Draw methode moeten deze klassen ook informatie hebben over de vorm. Een Line zou bijvoorbeeld een start en eindpunt kunnen hebben. In de Draw methode van Line wordt die informatie dan gebruikt om de lijn daadwerkelijk te tekenen. Een Circle zou een positie en een straal kunnen hebben, etc. Een 'meerpuntsfiguur' (Polygon) zou een array aan punten kunnen bevatten (waarbij niet gespecificeerd is hoeveel punten er in die array zitten, het kan er 1 of 3 of 91385 zijn).

Al deze informatie (punten, straal van cirkel, etc) zullen properties van je klassen Line, Circle etc worden.

Om deze informatie op te slaan heeft het .NET framework al een hele hoop klassen die je kunt gebruiken. De belangrijkste daarvoor is de Point klasse, wat gewoon een punt (x en y) op slaat.
Je zou dan uiteindelijk zoiets kunnen gebruiken om een nieuwe cirkel te maken en te tekenen:
code:
1
2
3
4
Point circleLocation = new Point(38, 190);
int radius = 5;
Shape circle = new Cirlce(circleLocation, radius);
circle.Draw();



Het uiteindelijke tekenen (de implementatie van de Draw methode) kan ofwel heel makkelijk zijn, ofwel heel moeilijk. Je geeft aan dat je graag een vector-tekening programma wilt maken. Daaruit maak ik op dat je graag wil dat je bijvoorbeeld oneindig kan inzoomen zonder kwaliteits verlies. Om dat te realiseren heb je heeeeel wat meer zooi nodig, waarschijnlijk veel wiskunde ook.

Het is veel makkelijker om een normaal "ala MS Paint" teken programma te maken. Dan kun je regelrecht gebruik maken van de Graphics klasse, die al heel veel teken methodes heeft. Bijvoorbeeld, Graphics.DrawLine, Graphics.DrawRectangle, Graphics.FillEllipse, etc. De naam geeft al aan wat de methode doet.

Al deze Graphics.Draw____ methoden zul je een Pen object mee moeten geven (en wat coordinaten)
code:
1
graphics.DrawLine(new Pen(Color.Red), x1, y1, x2, y2);  // deze volgorde denk ik


En alle Graphics.Fill____ methoden moet je een Brush object meegeven (en wat coordinaten). Je hebt verschillende soorten Brushes, bijvoorbeeld SolidBrush (één kleur) of LinearGradientBrush (een overloop van kleuren)
code:
1
graphics.FillRectangle(new SolidBrush(Color.Blue), rectangle);


Succes :)

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
huub8 schreef op zondag 25 april 2010 @ 21:01:
daar kwam in nog niet aan toe, maar ik geloof dat mijn leraar ongeveerd dit schema maakte:

- drawing
* tweepuntsfiguren
  • - lijn
  • - cirkel
  • - rechthoek
* meerpuntsfiguren
  • - veelhoek
  • - andere afwijkende meerpuntsfiguren
Meerpuntsfiguren heten trouwens polygonen.


Met deze opzet zou je zoiets kunnen doen

ShapeBase (abstract class of interface)
--SimpleShape (abstract class of interface, tweepunts figuren)
-----Line, Circle, Square
--Polygon (alle meerpunts figuren kun je hier in vangen, geef de constructor een array van punten en verbind die in volgorde met een lijn, vergeet niet de laatste en de eerste ook te verbinden! Met een 2e constructor die slechts het aantal hoeken en de straal als invoer vraagt kun je regelmatige veelhoeken maken. Gebruik in de constructor de sinus en cosinus om met stapjes van (2*pi)/aantalHoeken de juiste coordinaten uit te rekenen, stop deze in een array en roep daarna de eerste constructor aan.


Volgens mij is dit alles wat je nodig hebt. Btw als je interfaces wilt gebruiken, ipv abstract classes, zet dan een hoofdletter I voor de naam.

[ Voor 13% gewijzigd door roy-t op 26-04-2010 08:35 ]

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
ok, ik denk dat ik het princiepe nu goed begrijp. Maar ik heb nu weer een andere vraag :P :

Ik heb dus een tweepuntsfiguur classe, die een aantal fields bevat die voor line, cirkel en rechthoek van toepassing zijn, maar hoe moet ik deze fields dan instellen? Want het is dus de bedoeling dat ik een line object aanmaak en de constructor hiervan de benodigde waardes meegeef, moet deze consturtor van line dan ook de waardes voor het in erving hoger ligende tweepuntsfiguur doorkrijgen en deze instellen? Dus dat die protected worden?

Acties:
  • 0 Henk 'm!

  • Korben
  • Registratie: Januari 2001
  • Laatst online: 13-07 01:53

Korben

() => {};

huub8 schreef op maandag 26 april 2010 @ 16:46:
ok, ik denk dat ik het princiepe nu goed begrijp. Maar ik heb nu weer een andere vraag :P :

Ik heb dus een tweepuntsfiguur classe, die een aantal fields bevat die voor line, cirkel en rechthoek van toepassing zijn, maar hoe moet ik deze fields dan instellen? Want het is dus de bedoeling dat ik een line object aanmaak en de constructor hiervan de benodigde waardes meegeef, moet deze consturtor van line dan ook de waardes voor het in erving hoger ligende tweepuntsfiguur doorkrijgen en deze instellen? Dus dat die protected worden?
Als je lijn overerft van een interface, dan niet uiteraard. Bij een class is dat de vraag, als je je punten Point1 en Point2 noemt, is dat wel logisch, dan moet je inderdaad de constructor van de bovenliggende class protected maken en in je lijn-class de constructor als volgt definiëren:

C#:
1
2
3
4
5
6
public class Line: TwoPointShape
{
    public Line(Point point1, Point point2): base(point1, point2)
    {
    }
}


Als je echter je cirkel definieert, is het onduidelijk wat Point1 en Point2 betekenen; zijn dat twee punten op de omtrek van de cirkel of is één van de twee het midden en de ander een punt op de omtrek, en zo ja welke, of definieer je een middenpunt en een straal?

[ Voor 11% gewijzigd door Korben op 26-04-2010 17:21 ]

.oisyn: Échte programmeurs haten PHP met een passie. Ben jij soms geen echte programmeur?


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
Ik zou elke vorm klasse minimaal 1 punt laten hebben, noem dat Location, Position, of iets dergelijks. Dit punt stelt dan uiteindelijk de positie van het object voor. Wát die positie precies is hangt vaak van je vorm af. Voor een rechthoek zou ik de linker-boven hoek nemen. Voor een cirkel het middelpunt. Voor een lijn het start-punt, etc. Het maakt verder ook helemaal niet uit welk punt je (per vorm) definieerd als 'position', want dat is alleen van belang in de Draw methode. Je tekent je object natuurlijk op zijn eigen positie. Als jij de positie van je rechthoek graag in het midden definieert, dan hou je daar gewoon rekening mee in je Draw methode.

Wat heb je nu gewonnen zul je vragen? Heel simpel: je kunt deze property Location nu een laagje hoger implementeren: in de Shape klasse! Omdat elke vorm een positie moet hebben krijgt je Shape klasse gewoon een Location (van type Point dus) property, die dan elke vorm (die overerft van Shape) automatisch heeft.
Ook kun je dan, mocht je dat willen, een Move methode implementeren in je Shape klasse, in plaats van in elke vorm (line, rectangle, etc) apart. Je hoeft namelijk alleen de Location property te veranderen, en dan het object opnieuw te tekenen.

Hiermee heeft dus elke shape automatisch een positie en een methode waarmee je die shape kunt verplaatsen. Dit hoef je dus niet meer in elke klasse apart te implementeren.

Dit heeft meerdere voordelen, zoals het feit dat je geen repetitieve code (zelfde Move methode in elke klasse) meer hebt. Een veel belangrijker voorbeeld echter is dat je nu van een 'abstracte' Shape klasse de Move methode kunt aanroepen, of de Location property kunt gebruiken, zonder dat jij (of de compiler!) weet welke vorm het eigenlijk is! Sterker nog, die Shape die jij nu in je code gebruikt kan over een tijdje misschien een vorm voorstellen die je op dit moment nog niet eens gemaakt hebt!

Als je een lijstje met Shapes hebt:
code:
1
List<Shape> shapes = new List<Shape>();

dan gooi je daar, bijvoorbeeld, een paar vormen in:
code:
1
2
3
shapes.Add(new Line());
shapes.Add(new Circle());
shapes.Add(new Rectangle());

(voor het gemak heb ik de argumenten in de constructors maar even weg gelaten)

en dan kun je ergens anders van elke shape de Location opvragen, of de Move methode aanroepen, zonder dat je enig idee hebt wat voor shape het precies is (misschien wel een Triangle, die je nog niet gemaakt hebt)
code:
1
2
3
4
5
foreach (Shape s in shapes)
{
   MessageBox.Show(s.Location.ToString());   // toon positie
   s.Move(15, -30);   // verplaats met 15 pixels in de x-richting en -30 pixels in de y-richting, ofzo
}


Nu is de klasse Shape dus wel een klasse, en geen interface meer (een interface kan geen implementatie hebben, en de Location property en Move methode (waarin de Location property veranderd wordt) zijn implementaties). Omdat Shape nog altijd een Draw methode moet hebben die je nog niet kunt implementeren (immers, een Line teken je anders dan een Circle), en omdat je geen instantie van een Shape kunt maken (alleen van een Line, Circle, etc), moet je Shape een abstract class maken, en Draw een abstracte methode (daarmee wordt gegarandeerd dat elke klasse die van Shape overerft ook daadwerkelijk de Draw methode implementeert).


Ten slotte kun je nu ook goed nadenken over hoe je bepaalde vormen implementeert. Voor een rechthoek zou je bijvoorbeeld kunnen denken om, naast de Location (die bijvoorbeeld de linker-bovenhoek aangeeft) ook nog de rechter-onderhoek te gebruiken. Maar dat is niet zo handig, want wat moet de Move methode dan doen? Die zou ook de rechter-onderhoek moeten veranderen, maar dat kan niet want de klasse Shape (waarin de Move methode geimplementeerd is) heeft geen idee van die rechter-onderhoek.

In plaats daarvan kun je de breedte en hoogte aangeven. Die veranderen namelijk niet bij een verplaatsing. De Move methode verandert dus nu alleen de positie van de linker-bovenhoek, en de breedte en hoogte blijven onveranderd, dus is de rechthoek nu gewoon opgeschoven.

Voor een cirkel is het duidelijk: naast de Location gebruik je de straal, die ook niet veranderd.

Voor een lijn kun je de hoek (met de positieve x-as) en zijn lengte gebruiken (met wat basis wiskunde, trigonometrie, haal je daar in de Draw methode de positie van het eindpunt uit, om te tekenen).


EDIT
En om nog op je vraag terug te komen:

de (abstracte) Shape klasse kan in zijn constructor nu de positie (type Point) accepteren. In de constructor zet je dan de Location property:
code:
1
2
3
4
5
6
7
8
9
public abstract class Shape
{
   public Shape(Point location)
   {
      this.Location = location;
   }

   // Location property, Move en Draw methodes, etc...
}


Voor elke klasse die nu van Shape overerft kun je in ieder geval die positie als eerste argument, en mogelijk nog meerdere argumenten gebruiken. De positie geef je dan door aan de Shape constructor (mbv "base" zoals in de post boven mij), en de andere argumenten gebruik je in de huidige klasse:

code:
1
2
3
4
5
6
7
8
9
10
public class Circle : Shape
{
   public Circle(Point location, int radius)
      : base(location)
   {
      this.Radius = radius;
   }
 
   // Radius property en implementatie Draw methode, etc
}

De call naar "base" zet nu al de Location property, en de straal (Radius) wordt in deze klasse zelf gezet.

[ Voor 16% gewijzigd door NickThissen op 26-04-2010 19:15 ]

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • Reptile209
  • Registratie: Juni 2001
  • Laatst online: 12:56

Reptile209

- gers -

In aanvulling op het mooie verhaal van NickThissen: zorg dan dat je binnen de specifieke Shapes met relatieve coordinaten werkt ten opzichte van de Location. Een rechthoek loopt niet van (x1,y1) naar (x2,y2), maar heeft Location (x1,y1) met een Width en een Height. Je zou dan zelfs nog een Scale in de basisklasse kunnen opnemen, zodat je (in principe) makkelijk in- en uit kunt zoomen op je tekening door alleen de schaal aan te passen. Bij het tekenen van een Shape hoef je dan alleen de relatieve afmetingen met de schaal te vermenigvuldigen.
Iets te kort door de bocht: als je met meerdere Shapes gaat zoomen, zal de Location ook wel veranderen. Toch lijkt het me een nuttige feature om later verder uit te werken :).

Zo scherp als een voetbal!


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Reptile209 schreef op dinsdag 27 april 2010 @ 10:30:
Je zou dan zelfs nog een Scale in de basisklasse kunnen opnemen, zodat je (in principe) makkelijk in- en uit kunt zoomen op je tekening door alleen de schaal aan te passen.
Scale lijkt me juist niet een goede oplossing om dingen als zoomen te doen. Je moet gewoon zorgen dat het "Virtuele" coördinaten zijn, die niet perse 1 op 1 hoeven te matchen met het scherm. Pas op het moment dat er daadwerkelijk getekend word, moeten die coördinaten gewoon omgerekend worden naar de daadwerkelijk screen/image coördinaten.

gewoon in je Drawing class iets als ToScreenCoordinate(wordCoordinate) en ToWorldCoordinate(screenCoordinate)

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
Dan moet je toch nog altijd de grootte van het object weten (in world coordinates, ofwel relatief tov de andere shapes zeg maar), anders kun je nooit omrekenen van world naar screen coordinates.

De grootte (Size bijvoorbeeld) is inderdaad ook iets wat je in de Shape klasse kan implementeren, zolang alle vormen (die van Shape overerven) die informatie maar gebruiken om zichzelf te tekenen. Het ligt er maar net aan of je dit nodig hebt. Als je de vormen wilt kunnen resizen dan zal het moeten. Als je wilt kunnen zoomen waarschijnlijk ook (hoewel dat weer een stuk ingewikkelder ligt).

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Objecten moeten dan alle informatie hebben om de positie/vorm/formaat in world-space te kunnen bepalen. Een shape moet dus al zijn punten in wold-space kunnen bepalen. Een coordinaat in world space kun je eenvoudig omrekenen naar screen-space afhankelijk van hoe je je world af wil beelden. Je hebt dan een view die naar een bepaald gedeelte van de world kijkt. De view heeft dus alle informatie om world coördinaten om te rekenen naar screen coördinaten.

Het zoomen veranderd dan niks aan de objecten zelf, het is immers ook alleen de presentatie van de objecten. Als een object daadwerkelijk van grootte veranderd dan moet dat natuurlijk wel in world space gebeuren.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
Sorry, ik dacht dat je bedoelde dat een grootte van een object niet nodig was om zoom te implementeren. Maar je bedoelde de Scale methode, eg een verandering van de grootte. Dat heeft inderdaad niets met zoomen te maken (hoewel het waarschijnlijk wel nuttig is ;) ).

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • LPEspecial
  • Registratie: September 2004
  • Laatst online: 15-07-2024
Een praktisch probleem waarvoor ik hier nog geen oplossing zie is dat rechthoeken niet altijd precies horizontaal liggen. Een rechthoek kan ook een bepaalde hoek hebben, vergeet dit niet om een hoger punt te krijgen (er zijn een onbeperkt aantal mogelijkheden om een rechthoek door 2 punten te tekenen, of om een rechthoek met een bepaalde positie, breedte en hoogte te tekenen).

LPEspecial


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
LPEspecial schreef op dinsdag 27 april 2010 @ 12:17:
Een praktisch probleem waarvoor ik hier nog geen oplossing zie is dat rechthoeken niet altijd precies horizontaal liggen. Een rechthoek kan ook een bepaalde hoek hebben, vergeet dit niet om een hoger punt te krijgen (er zijn een onbeperkt aantal mogelijkheden om een rechthoek door 2 punten te tekenen, of om een rechthoek met een bepaalde positie, breedte en hoogte te tekenen).
In feite kun je elk object roteren natuurlijk, en dus zou je in je base class gewoon een rotatie op kunnen nemen. Nou is dat voor een cirkel niet zo nuttig, maar ook polygonen kun je roteren. Je zou dat kunnen doen door daadwerkelijk de punten van het figuur aan te passen, of een extra rotatie bij houden.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Als je gewoon een matrix opslaat hoef je geen positie, rotatie of schaal op te slaan dit is staat namelijk allemaal in de matrix.

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
Heel erg bedankt voor de vele reacties en daarmee vele ideeen. De basis heb ik nu al bijna af, en is tevens goedgekeurd door mijn leraar :P.

Acties:
  • 0 Henk 'm!

  • Alex)
  • Registratie: Juni 2003
  • Laatst online: 21-08 11:20
Nou ben ik wel benieuwd wat je basis is geworden :)

We are shaping the future


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
ik zal het programma wel hier posten als het klaar is :)
Pagina: 1