stratton
stratton

Reputation: 9

Edit properties of Graphics object c#

I'm currently trying to implement alternating colors using Threads for a Graphics object on a Windows Form in C#.

The code to draw a line works as follows:

 public void DrawLine(int toX,int toY) //draw line
    {
        g.DrawLine(currPen, xPos, yPos, toX, toY);
        xPos = toX;
        yPos = toY;
    }

The variables assigned at the top of the Canvass class are as follows:

    Graphics g;
    public static Pen Red, Blue, Green, redGreen;
    public static int xPos, yPos;
    public static Pen currPen;
    public static Thread newThread;
    public static bool flag = false;
    public static bool running = false;

The method of thread so far changes the color of the box which will be used to turn on flashing colors (This method is currently inside another class and will interact with static void's inside the Canvass class):

private void pictureBox6_Click(object sender, EventArgs e)
    {
        running = !running;
    }

    public void redgreenMethod()
    {
        while (true)
        {
            if (running != true) continue;
            if (flag == false)
            {
                flag = true;
                pictureBox6.BackColor = Color.Red;
            }
            else
            {
                pictureBox6.BackColor = Color.Green;
                flag = false;
            }
            Thread.Sleep(500);

        }

    }

My issue is, I'm not too sure how to implement the threading onto a line on the Graphics canvass.. As seen in the Threads method, it interacts with the background colour of a pictureBox, whereas this kind of property isn't available for a line being drawn.

How do I approach this?

Upvotes: 0

Views: 219

Answers (2)

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112259

GDI+ (that's the library you are using when drawing in a WinForms application) does not store the things you are drawing as objects but only sets pixel colors.

You must create your own object model to have access to these objects. Example

public abstract class Shape
{
    public Pen Pen { get; set;}

    public abstract void Draw(Graphics g);
}

public class Line : Shape
{
    public Point From { get; set; }
    public Point To { get; set; }

    public override void Draw(Graphics g)
    {
        g.DrawLine(Pen, From, To);
    }
}

... other shapes

Then you would create a list of shapes

private readonly List<Shape> Shapes = new();

and in the Paint event handler you draw the graphic

private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
    Graphics g = e.Graphics;
    foreach (Shape shape in Shapes) {
        shape.Draw(g);
    }
}

Now, instead of directly drawing things you would add new shapes to the list of shapes and invalidate the picture box to have it redrawn

public void DrawLine(int toX,int toY) //draw line
{
    Shapes.Add(
        new Line {
            Pen = currPen,
            From = new Point(xPos, yPos),
            To = new Point(toX, toY)
        }
    );
    xPos = toX;
    yPos = toY;
    pictureBox1.Invalidate();
}

You can user a Timer object to time and trigger your animation. Note that the Timer.Tick event is raised in the UI thread, so that you will not run into multithreading issues.

See also this answer to the How to Draw Lines with delay? question.

It is important not to draw directly and to delegate this work to the Paint event handler, because this paint event might also be triggered, e.g., when another window on top of your application is closed. On the other hand, e.g., when your application is iconized, this event will not be triggered.

You can also reduce flicker by setting pictureBox1.DoubleBuffered = true;.

Upvotes: 2

Oogamar
Oogamar

Reputation: 21

What your looking for is the Timer object https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.timer?view=windowsdesktop-6.0

add it to your win forms using the toolbox enable it in the properties and add the event by double clicking on it

private void pictureBox1_Click(object sender, EventArgs e)
{
    running = !running;

    if (running)
        iter = 0
    else
        iter = -1
}

private void timer1_Tick(object sender, EventArgs e)
{
    switch (iter)
    {
        case 0:
            pictureBox1.BackColor = Color.Red;
            iter++;
            break;
        case 1:
            pictureBox1.BackColor = Color.Green;
            iter = 0;
            break;
    }
}

don't forget to add your iterator int to your class

private int iter = 0;

Upvotes: 2

Related Questions