SN25 Ответов: 1

Как две разные графики строятся параллельно с помощью C#


Приветствую Всех,

Мне нужна помощь, чтобы построить две графики (разного стиля (точечная и прямоугольная точка)) параллельно, используя одни и те же данные на изображении. Эта графическая программа выполняется следующим образом:

1. читает текстовый файл, содержащий точки данных, которые должны быть нанесены на файл изображения, который загружается в поле изображения.

2. Программа использует кнопки и флажок.

3.после нажатия кнопки вверх выполнение программы начиналось с построения первого графика, однако при установке флажка второе графическое построение начиналось параллельно первому графику, а при снятии флажка второе графическое построение прекращалось. (Оба графических стиля используют один и тот же текстовый файл).

4. второй график фактически строит траекторию (непрерывный график / график отслеживания) первого графика. Как и тогда, когда пользователь хочет наблюдать траекторию (график отслеживания), поэтому установите флажок.

5. Я использовал технику резьбы, чтобы прочитать текстовый файл и активирует эту ветку под кнопки.

Мне нужна помощь, что делать в этом случае, должен ли я создать отдельный поток для флажка для построения второго графика параллельно с первым?

здесь я делюсь блоком своего кода, который я пытался реализовать, но он строит первую графику, и когда флажок установлен, программа строит первую и вторую графики непрерывно, что не соответствует моим требованиям программы. Я хочу построить прямоугольную точку непрерывно (трек-график) в качестве второго графика, когда флажок установлен.

Пожалуйста, помогите!

Что я уже пробовал:

public partial class Form1 : Form
{ 
    double x;
    double y;
    Thread T;
    int F;
    delegate void refresh();
    private System.Drawing.Graphics g;
    

    public Form1()
    {
        InitializeComponent();
    }

    void refresh_PicBox()
    {
        if (pictureBox1.InvokeRequired)
        {
            refresh r = new refresh(refresh_PicBox);
            pictureBox.Invoke(r);
        }
        else
        {
            pictureBox.Refresh();
        }
    }

    public void block()
    {
        StreamReader file = new StreamReader(@"C:\Text.txt");
        string line;
        int sc = 100;
       
        while ((line = file.ReadLine()) != null)
        {
            char[] del = new char[] { '\t' };
            string[] part = line.Split(del, StringSplitOptions.RemoveEmptyEntries);

            w = Convert.ToDouble(part[0]) * sc;
            z = Convert.ToDouble(part[1]) * sc;

            g = pictureBox.CreateGraphics();
            if (flag == 0)
            {
                g.DrawImage(new Bitmap(@"C:\interface.png"), Convert.ToInt32(w), Convert.ToInt32(z), 20, 20);
                Thread.Sleep(50);
                refresh_PicBox();// invoke for refreshing picture box

            }
            if (flag == 1)
            {
             g.DrawImage(new Bitmap(@"C:\interface.png"), Convert.ToInt32(w), Convert.ToInt32(z), 20, 20);
             refresh_PicBox();
             g.FillRectangle(Brushes.Blue, Convert.ToInt32(w), Convert.ToInt32(z), 9, 9); 
             Thread.Sleep(50);
            }
        }
    }
    
    private void Form1_Load(object sender, EventArgs e)
    {
        pictureBox.Image = new Bitmap(@"C:\Image.jpg");
    }
    
    private void button_Click(object sender, EventArgs e)
    {
        T = new Thread(block);
        T.Start();
        flag = 0;
    }

    private void checkBox_CheckedChanged(object sender, EventArgs e)
    {
        if (checkBox.Checked)
        {
            flag = 1;
        }
        else
        {
            flag = 0;
        }
    }
}

1 Ответов

Рейтинг:
1

Graeme_Grant

Я бы:
1. есть объект класса, который используется для построения целевой элемент управления PictureBox
2. Создайте объект для каждого участка, проходящего по изображению, точкам участка и целевому холсту (PictureBox)
3. запустите таймер и на каждом ТИКе попросите каждого (в зависимости от флажка) построить следующую точку

Это было бы:
1. устраните необходимость использования нитей
2. таймер контролирует частоту обновления, больше никаких потоков.Сон(...)
3. Удалите дубликат кода
4. сгруппируйте связанный код вместе, чтобы облегчить его чтение и отладку.

Таким образом, вы закончите с чем-то вроде этого:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        LoadSeries();
        HookTimer();
    }

    private void butPlot_Click(object sender, EventArgs e)
    {
        completedCount = 0;
        plotTimer.Start();
    }

    private List<Series> Series;

    private void LoadSeries()
    {
        Series = new List<Series>
        {
            new Series(picPlotCanvas, MarkerType.Rectangle, Color.Blue)
            {
                Points = new List<PointF>
                {
                    new PointF(0f, 0f),
                    new PointF(1f, 1f),
                    new PointF(2f, 2f),
                    new PointF(3f, 3f),
                }
            },
            new Series(picPlotCanvas, MarkerType.Triangle, Color.Red)
            {
                Points = new List<PointF>
                {
                    new PointF(0f, 0f),
                    new PointF(1f, 1f),
                    new PointF(2f, 2f),
                    new PointF(3f, 3f),
                }
            }
        };

        foreach (var series in Series)
        {
            series.Done += Series_Done;
        }
    }

    private int completedCount;
    private void Series_Done(object sender, EventArgs e)
    {
        completedCount++;
    }

    // update every 100ms
    private readonly Timer plotTimer = new Timer { Interval = 100 };

    private void HookTimer()
    {
        plotTimer.Tick += Timer_Tick;
    }

    private void Timer_Tick(object sender, EventArgs e)
    {
        if (chkDualPlot.Checked ? completedCount < Series.Count : completedCount == 0)
        {
            Series[0].NextPoint();

            // do we plot the second series?
            if (chkDualPlot.Checked)
                Series[1].NextPoint();
        }
        else
        {
            // We're done!
            plotTimer.Stop();
        }
    }
}

internal enum MarkerType
{
    Rectangle,
    Triangle
}

internal class Series
{
    public Series(PictureBox canvas, MarkerType marker)
        : this(canvas,marker,Color.Red) { }

    public Series(PictureBox canvas, MarkerType marker, Color color)
    {
        this.canvas = canvas;
        Marker = marker;
        Color = color;
    }

    public event EventHandler Done;

    public MarkerType Marker { get; set; }
    public Color Color { get; set; }
    public List<PointF> Points { get; set; }

    private PictureBox canvas;
    private int currentIndex;

    public void NextPoint()
    {
        if (Points == null)
            throw new NoNullAllowedException();

        if (currentIndex < Points.Count)
        {
            // Draw point on canvas
            Debug.WriteLine($"plotting point: {currentIndex} Marker: {Marker.ToString()}");

            currentIndex++;
        }
        else
        {
            currentIndex = 0;
            Done?.Invoke(this, EventArgs.Empty);
        }
    }
}

Я оставлю чертежную часть на ваше усмотрение. :)


SN25

Спасибо Graeme_Grant за ваши усилия я попробую ваш подход

Graeme_Grant

Пожалуйста. :)

Если вы запустите код "как есть" и посмотрите окно вывода отладки, вы увидите, что он делает именно то, что вы хотите. Все, что вам нужно сделать сейчас, это добавить поддержку изображения (не маркера) и добавить код для рендеринга изображения на холсте (PictureBox).

Кроме того, что может быть неясно, так это то, что если несколько серий (более 2 могут быть использованы) не имеют одинакового количества точек, код будет изящно обрабатывать их.

Наслаждаться.