Avatar billede benjif Nybegynder
15. juni 2004 - 01:11 Der er 13 kommentarer og
2 løsninger

Tegning med gdi+

Jeg sidder og skal lave et mindre tegne program i c# men har nogen problemer med at finde ud af hvordan jeg kan tegne samtidig med jeg flytter musen. Er der nogen der kan forklare mig hvordan man gør.
Så vidt jeg har fundet ud af ser det ud som det har fjernet Draw modes som gjorde det muligt at tegne med xor mode så det ser pænt ud.
Det eneste jeg har fundet var disse funktioner til at tegne direkte på kontrollen:
ControlPaint.DrawReversibleLine
ControlPaint.DrawReversibleFrame

men der kan jeg ikke tegne cirkler og jeg kan heller ikke sætte tykkelsen på pennen.

jeg overvejede også at nedarve fra Graphics klassen og implementere noget funktionalitet fra windows api, men da klassen var endelig kunne jeg heller ikke gøre dette.

Så jeg er lidt lost nu :(

Nogen som har nogen gode ideer
Avatar billede kaffe Nybegynder
15. juni 2004 - 08:56 #1
Et lille udkast her fra morgenstunden.
Tegningen foregår i et panel (Panel1) på en alm. windows form.
Der er 2 knapper (buttonDraw og buttonCircle) og en textbox hvori bredden af pennen skrives.

enum drawMode{
    none,    // tegn ikke (ikke implementeret)
    draw,    // alm. tegning
    circle,    // tegn cirkel
    square      // tegn firkant (ikke implementeret)
}

private drawMode dMode;

private void buttonDraw_Click(object sender, System.EventArgs e) {
    dMode = drawMode.draw;
}

int oldX, oldY;
       
private void panel1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
    if(e.Button == MouseButtons.Left){
    Pen pen = new Pen(new SolidBrush(Color.Black), (float)Convert.ToInt32(textBoxPenWidth.Text));
    Graphics grfx = panel1.CreateGraphics();
    switch(dMode){
    case drawMode.draw:
        grfx.DrawLine(pen, oldX, oldY, e.X, e.Y);
        oldX = e.X;
        oldY = e.Y;
            break;
    case drawMode.circle:
        //Vent på mouseup og tegn cirklen       
        break;
    }
    }
}

private void panel1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
    oldX = e.X;
    oldY = e.Y;
}

private void panel1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) {
    if(dMode == drawMode.circle){
    Pen pen = new Pen(new SolidBrush(Color.Black), (float)Convert.ToInt32(textBoxPenWidth.Text));
    Graphics grfx = panel1.CreateGraphics();
    if(oldX > e.X && oldY > e.Y)
    grfx.DrawArc(pen, e.X, e.Y, oldX - e.X, oldY - e.Y, 0, 360);
    else if(oldX > e.X && oldY < e.Y)
    grfx.DrawArc(pen, e.X, oldY, oldX - e.X, e.Y - oldY, 0, 360);
    else if(oldX < e.X && oldY > e.Y)
    grfx.DrawArc(pen, oldX, e.Y, e.X - oldX, oldY - e.Y, 0, 360);
    else
    grfx.DrawArc(pen, oldX, oldY, e.X - oldX, e.Y - oldY, 0, 360);
    }
}

private void buttonCircle_Click(object sender, System.EventArgs e) {
    dMode = drawMode.circle;
}

Go' fornøjelse
Avatar billede benjif Nybegynder
15. juni 2004 - 13:21 #2
Jeg kan umildbart ikke se ud fra de kode hvordan jeg f.eks kan tegne en cirkel mens jeg flytter mussen, du tegner cirklen efter du slipper musen. Det jeg er udeefter er at kunne tegne en cirkel mens jeg flytter mussen hvor den sletter den gamle cirkel så der ikke er 300 cirkler på skærmen når man rykker rundt på musen. I MFC verden tror jeg det hedder XOR mode som sletter den gamle cirkel ved at tegne cirklen oven i igen
Avatar billede apocryphal Nybegynder
17. juni 2004 - 10:21 #3
Min løsning (Jeg laver en seperat kommentar, hvor jeg kommenterer den nøjere):
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace CircleTest
{
    public class Form1 : System.Windows.Forms.Form
    {
        private System.ComponentModel.Container components = null;
        private bool IsMouseDown = false;
        private int CircleStartX = 0, CircleStartY = 0;
        private int CircleX = 0, CircleY = 0;
        private int CircleR = 0;

        public Form1()
        {
            InitializeComponent();
            Paint += new PaintEventHandler(DoPaint);
            MouseDown += new MouseEventHandler(DoMouseDown);
            MouseUp += new MouseEventHandler(DoMouseUp);
            MouseMove += new MouseEventHandler(DoMouseMove);
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
        }

        private void DoMouseDown(object sender, MouseEventArgs e)
        {
            IsMouseDown = true;
            CircleStartX = e.X;
            CircleStartY = e.Y;
            CircleX = e.X;
            CircleY = e.Y;
        }

        private void DoMouseUp(object sender, MouseEventArgs e)
        {
            IsMouseDown = false;
        }

        private void DoMouseMove(object sender, MouseEventArgs e)
        {
            CircleX = e.X;
            CircleY = e.Y;
            //Pythagoras
            int A = Math.Abs(CircleX-CircleStartX);
            A *= A; //Powered by 2
           
            int B = Math.Abs(CircleY-CircleStartY);
            B *= B;

            int C = (int)Math.Sqrt((double)(A+B));
            CircleR = C;
            Invalidate();
        }

        private void DoPaint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
           
            if(IsMouseDown)
            {
                g.DrawRectangle(Pens.Blue, CircleStartX, CircleStartY, 1, 1);
                PaintCircle(g, CircleStartX, CircleStartY, CircleR);
            }
        }

        private void PaintCircle(Graphics g, int x, int y, int r)
        {
            g.DrawEllipse(Pens.Red, x-r, y-r, r*2, r*2);
        }

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

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(292, 273);
            this.Name = "Form1";
            this.Text = "Form1";

        }
        #endregion

        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }
    }
}
Avatar billede apocryphal Nybegynder
17. juni 2004 - 10:27 #4
Her er så en beskrivelse af, hvad der sker:

Contructoreren:
Binder fire events: Paint, MouseDown, MouseUp og MouseMove - dem skal vi bruge.

Med PaintEventet, får vi mulighed for selv at tegne på Controllen (Windows Formens's) Canvas.

- bemærk dette statement:
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);

Hvis vi ikke gør det, så flimrer det mens vi flytter musen - .NET's svar på DoubleBuffering - med kun én linje kode.

De tre Museevents:
Når musen trykkes ned, sætter jeg Cirklens centrum koordinat, samt et punkt på cirkel periferien (Cirkelsn ligning, anyone?).

I MouseUp, sætter jeg boolean variablen - IsMouseDown, til false... Navnet giver sig selv.

MouseMove.
Her flytter vi punktet på cirkel periferien, og udregner en ny radius. Da jeg desværre ikke kan huske Cirklens ligning uden at konsulterer min matematikbog fra 1G, så bruger jeg bare Pythagoras's ligning til at finde radius på cirklen.

DoPaint:
Hvis IsMouseDown er true, så tegner den en cirkel, med den dertil skabte funktion.
Da der ikke er en DrawCircle funktion, bruger jeg en elipse, med identisk højde og brede - derfor den lidt omskrevede funktion PaintCircle.

--

Jeg håber det var dét du mente med dit spørgsmål :)

--
Jonas
Avatar billede benjif Nybegynder
17. juni 2004 - 11:21 #5
det var lige præsis det jeg mente ved du hvordan jeg skal håndtere det hvis jeg ikke skal tegne direkte på formen men i en control som en picturebox?
Avatar billede apocryphal Nybegynder
17. juni 2004 - 11:55 #6
Du kan lave en klasse, hvor du nedarver fra f.eks. UserControl, og bruge den samme fremgangsmåde.

Da dette emne også er en god øvelse for mig, kan jeg godt lave et eksempel på det, hvis det er til hjælp for dig :)

Hvordan præcis vil du implementerer det i din applikation?

--
Jonas
Avatar billede benjif Nybegynder
17. juni 2004 - 12:01 #7
mange takker :) jeg har en document klasse som er en user control som indeholder en picture box hvor jeg skal kunne tegne i, og flytte rundt på de forskellige figure, men det med at flytte rundt på tingene burde ikke være noget problem når det andet er på plads.
Avatar billede apocryphal Nybegynder
17. juni 2004 - 12:04 #8
Så ville jeg lave min egen UserControl (DrawBoard, ville jeg nok klade den), og sætte den ind der hvor picture boxen er.

I DrawBoard ville jeg implementerer den samme kode, som jeg har i ovenstående eksempel.

Jeg laver et eksempel på det om 1½ time eller sådan noget. Jeg skal lige afslutte nogle andre opgaver først... Business before pleasure - desværre :P

--
Jonas
Avatar billede benjif Nybegynder
17. juni 2004 - 12:20 #9
jeg har lige selv siddet og rodet lidt med det. jeg kan ikke helt forstå du vil nedarve fra usercontrols er det ikke nemmenre at nedarve direkte fra picturebox klassen. Det har jeg lige gjort og det virker
Avatar billede benjif Nybegynder
17. juni 2004 - 12:22 #10
men er det den rigtige måde at gøre det på, eller burde man gøre det fra usercontrol sådan som jeg ser det virker det mere logisk at gøre det direkte fra picturebox
Avatar billede apocryphal Nybegynder
17. juni 2004 - 12:43 #11
Det er "forkert" at bruge PictureBox, da de funktioner du bruger (Paint, MouseMove, MouseDown og MouseUp), kommer fra klassen System.Windows.Forms.Control (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformscontrolclasstopic.asp)

Jeg forslog UserControl klassen (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformscontrolclasstopic.asp), så den opfører sig bedre i Visual Studio .NET - altså så du kan bruge WYSIWYG på den.

Men vil du tegne Cirklerne oven på et billede?
- i såfald giver det fin mening at bruge PictureBox :)

Det virker fint i PictureBox - fordi den nedarver direkte fra Control.

Hvis du ikke har planer om at bruge noget af det PictureBox kan, så implementerer du bare en masse kode som du alligevel ikke skal bruge. Det undgår du ved at bruge Control direkte.

--
Jonas
Avatar billede benjif Nybegynder
17. juni 2004 - 13:14 #12
det jeg skal er sådanset bare at kunne tegne et statediagram og kunne generere noget xml ud fra det og herudover kunne gemme billedet som bitmap ud fra det jeg har tegnet. jeg skal ikke kunne tegne oven i et billede der. Så bør jeg ikke nedarve fra picture box vel såvidt jeg kunne forstå vel ?
Avatar billede apocryphal Nybegynder
17. juni 2004 - 13:20 #13
Nope, så behøver du bare Control-klassen.

Har du flere spørgsmål, eller skal jeg have mine points? ;)

--
Jonas
Avatar billede benjif Nybegynder
17. juni 2004 - 13:26 #14
nope ikke mere mange takker for hjælpen :D
Avatar billede apocryphal Nybegynder
17. juni 2004 - 13:27 #15
Svar svar.... Give me points....
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester