Удаление старых label с данными при загрузке новых данных из файла

147
01 января 2020, 21:00

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

Необходимо выводить значения столбцов из файла над ними.

Решил пойти самым простым путём и для каждой строки, прочитанной из файла создаётся label. Проблем несколько:

1) Координаты label'ов сбиты. Чем больше значение, тем ниже находится текст (скриншот прикрепил), а хочется, чтобы значения выводились прямо над столбцами

2) При загрузке новых данных label остаются и добавляются новые поверх старых. Нужно как-то предусмотреть удаление старых. Рассчитываю хотя бы на совет, в каком направлении думать.

Возможно, значения вообще можно как-то вывести по-другому и более красиво, но для себя усмотрел именно такой вариант.

Пробовал циклы, так же безуспешно. Выносил Label namelabel = new Label(); за пределы метода и добавлял в обработчик кнопки очищение формы от label'ов, но после нажатия кнопки для записи новых данных обе кнопки пропадали и с приложением, понятное дело, работать невозможно.

Сам код:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    Pen coord = new Pen(Color.Black);
    public List<int> massive = new List<int>();
    private void Form1_Paint(object sender, PaintEventArgs e) //Рисуем оси
    {
        Graphics g = e.Graphics;
        g.TranslateTransform(50, 213);
        g.DrawLine(coord, 0, -200, 0, 200); //Y axis (ось)
        g.DrawLine(coord, 0, 0, 700, 0); //X axis (ось)

    }
    Random wrd = new Random();
    public void write_all() //Записываем значения в файл 
    {
        var lines = new List<string>(); // сюда сложим все строки, что будем писать в файл
        for (int b = 1; b < 10; b++)
        {
            // wrd.Next(5, 120) генерирует число, чтобы превратить его в строку, вызываем .ToString()
            lines.Add(wrd.Next(5, 120).ToString());
        }
        File.WriteAllLines(@"C:\test\graphs.txt", lines);
    }

    private void draw_all(List<int> massive) //Рисуем столбцы, прочитав значения из ранее созданного файла
    {
        Pen rec = new Pen(Color.Black);
        Random rclr = new Random();
        SolidBrush filler = new SolidBrush(Color.FromArgb(rclr.Next(0, 256), rclr.Next(0, 256), rclr.Next(0, 256)));
        Graphics g = this.CreateGraphics();
        g.TranslateTransform(0, 213);
        int x = 53;
        Random graphs = new Random();
        int visota;
        for (int i = 0; i < 10;)
        {
            string[] readText = File.ReadAllLines((@"C:\test\graphs.txt"));
            foreach (string w in readText)
            {
                visota = Convert.ToInt32(w);
                Rectangle rect = new Rectangle(x, 0 - visota, 30, visota);
                g.FillRectangle(filler, rect);
                filler.Color = Color.FromArgb(rclr.Next(0, 256), rclr.Next(0, 256), rclr.Next(0, 256));
                x = x + 80;
                i++;
                foreach (string a in readText)
                {
                        Label namelabel = new Label();
                        namelabel.AutoSize = false;
                        namelabel.Size = new System.Drawing.Size(25, 15);
                        namelabel.Location = new Point(x - 77, visota);
                        namelabel.Text = visota.ToString();
                        Controls.Add(namelabel);
                }
            }
            i++;

        }
    }
    private void button2_Click(object sender, EventArgs e) //Вывод на форму (Кнопка прочитать)
    {
        Refresh();
        draw_all(massive);
    }
    private void button1_Click(object sender, EventArgs e) //Запись значений и создание файла со значениями
    {
        write_all();
    }
}
Answer 1

Для комментария многовато будет, поэтому пусть полежит здесь.

Несколько простых советов.

  1. Если вы все рисуете самостоятельно, то текст для колонок также стоит именно рисовать (см. Graphics.DrawString). В дальнейшем при очистке или обновлении изображения не возникнет необходимости отдельно обновлять колонки и надписи.

  2. Выносите метод рисования одной колонки и надписи над ней в отдельный метод с необходимыми параметрами (размер, текст, положение, цвет и т.д.). Это позволит упростить код цикла и упростить отладку.

  3. Не рисуйте прямо на форме. Создайте наследника UserControl и разместите код отрисовки в виртуальном методе OnPaint. Это позволит автоматически обновлять изображение после изменения состояния окна.

  4. Не рисуйте рандомно. Генерируйте случайный набор данных для рисования. Код рисования вообще не должен знать как именно вы получили данные для рисования.

Ну и последнее, иногда стоит посмотреть исходники существующих компонентов, даже если по заданию/желанию необходимо все сделать самостоятельно.

Answer 2

Для отображения гистограммы и других подобных вещей, есть объект Chart (подробнее про объект Chart). Перенесите его на форму из панели элементов (находится в разделе Data). Объект появился в .NET Framework 4.0, если у вас версия 3.5, есть возможность скачать и установить этот объект отдельно по следующей ссылке: https://www.microsoft.com/ru-ru/download/details.aspx?id=14422.

С помощью данного объекта вашу задачу реализовать проще и удобнее:

    public Form1()
    {
        InitializeComponent();
        // Установить метку над столбцом
        chart1.Series["Series1"].IsValueShownAsLabel = true;
    }
    string fileName = "graphs.txt";
    Random wrd = new Random();
    public List<int> massive = new List<int>();
    public void write_all() // Записываем значения в файл 
    {
        var lines = new List<string>(); // Сюда сложим все строки, что будем писать в файл
        for (int b = 1; b < 10; b++)
        {
            lines.Add(wrd.Next(5, 120).ToString());
        }
        File.WriteAllLines(fileName, lines);
    }
    private void draw_all(List<int> massive) // Рисуем столбцы, прочитав значения из ранее созданного файла
    {
        int i = 0;
        Random rclr = new Random();
        string[] readText = File.ReadAllLines((fileName));
        // Удаляем старые значения точек
        chart1.Series["Series1"].Points.Clear();
        foreach (string y in readText)
        {
            // Добавляем столбец (положение по прямой - X, высота - Y)
            chart1.Series["Series1"].Points.AddXY(i+1, Convert.ToDouble(y));
            // Указываем цвет
            chart1.Series["Series1"].Points[i].Color = Color.FromArgb(rclr.Next(0, 256), rclr.Next(0, 256), rclr.Next(0, 256));
            i++;
        }
    }
    private void button2_Click(object sender, EventArgs e) // Вывод на форму (Кнопка "Загрузить")
    {
        draw_all(massive);
    }
    private void button1_Click(object sender, EventArgs e) // Запись значений и создание файла со значениями (Кнопка "Записать")
    {
        write_all();
    }
READ ALSO
Как добавить SVG в трей?

Как добавить SVG в трей?

Приложение - WinFormsВ трее есть иконка - использовал NotinfyIcon, но вот тут я столкнулся с проблемой качества иконок

212
Перенос кода с vb на с#

Перенос кода с vb на с#

Помогите перенести код с vb на C#

156
Почему тормозит TreeView?

Почему тормозит TreeView?

При большом количестве веток дерева, у меня начинает тормозить TreeView, а точнее, обычная операция присвоения имени ветки:

185