Последние изменения - Поиск:
RSS блога RSS блога

Начало

Программки

Плагины

Софт-обзоры

Программирование

Фото

Разное

Блог

Контакты

Я в FriendFeed Я в ЖЖ Я в твиттере

Шпаргалка по ZedGraph

Оглавление

Введение

ZedGraph - это очень удобный компонент для рисования графиков под .NET Framework, но, к сожалению, документация к этому контролу довольно скудная. Поэтому здесь я решил сделать что-то вроде шпаргалки или, если угодно, HOWTO по компоненту ZedGraph.

То, что находится дальше на этой странице - это не справка, а просто небольшие примеры, показывающие как использовать какую-нибудь одну из возможностей контрола. Все основные пояснения по использованию той или иной возможности будут написаны в виде комментариев к коду.

Структура всех примеров одинаковая - главное окно, внутри которого располагается экземпляр класса ZedGraphControl. Имя экземпляра класса - zedGraph. В конструкторе окна вызывается метод DrawGraph(), внутри которого и происходит заполнение компонента данными. Поэтому в примерах ниже будут приводиться только функции DrawGraph() и дополнительные функции, которые будут зависеть от примера.

Все примеры объединены в одном solution для Visual Studio 2005 и написаны на языке C#, скачать их можно отсюда.

Эта шпаргалка со временем будет пополняться новыми примерами.

Если у вас есть вопросы, которые требуют большого количества кода, то пишите их лучше на форум, остальные вопросы и пожелания можете писать в комментариях.

Краткие сведения о ZedGraph и полезные ссылки

Официальный сайт ZedGraph - http://zedgraph.org
Требования - .NET 1.1 (для версии 4.x) или .NET 2.0 (для версии 5.x)
Страница документации - http://zedgraph.sourceforge.net/documentation/default.html
Еще есть неплохой материал на сайте CodeProject, с которого хорошо начинать изучение этого компонента - http://www.codeproject.com/KB/graphics/zedgraph.aspx

Пожалуйста, оцените материал

5 stars Рейтинг 5.0/5. Всего 36 голос(а, ов)



Автор:
Тема:
 Ваш комментарий
 
 
Введите код 659
 

Daisy 05.12.2008 - 03:05

Большое спасибо, очень помогли! happy smiley

Jenyay 05.12.2008 - 09:22

Очень приятно :)

Anton 18.12.2008 - 12:24

А как установить ширину

никак не получается задать ширину отдельного GraphPane в MasterPane. Как это сделать? У меня три столбиковых диаграммы и в каждой разное количество баров, надо, чтобы в отдельная диаграмма занимала место (в ширину) в зависимости от количества баров в ней относительно других в этомже MasterPane

Jenyay 18.12.2008 - 21:30

Anton, С MasterPane я как раз разбираюсь, но по Вашему вопросу пока ничего сказать не могу. В ближайшее время выложу пример с MasterPane, заодно посмотрю можно ли там вручную задавать размеры и расположение отдельных Pane.

Anton 19.12.2008 - 13:37

Короче сам разобрался

В этой функции вычисляю размер необходимый для выделения под GraphPane

Private Function CalcPaneWidth(ByVal allElementsCnt As Single, ByVal paneElementsCnt As Single, ByVal panesWidth As Single) As Single
        Dim ReturnValue As Single = 0
        Dim OnePercent As Double = (panesWidth / allElementsCnt) 'Ширину MasterPane делю на общее количесво баров
        Dim paneWidthPercent As Double = (paneElementsCnt * OnePercent) 'Умножаю на количество баров в конкретном GraphPane
        ReturnValue = CType(paneWidthPercent, Single)
        Return ReturnValue
    End Function

В коде где заполняю графики пишу

SmallRect = mPane.Rect
        SmallRect.Y = 45
        SmallRect.Height = mPane.Rect.Height - 45

        For PaneIndex = 0 To mPane.PaneList.Count - 1

            mPane.Item(PaneIndex).XAxis.IsVisible = True
            mPane.Item(PaneIndex).XAxis.Type = AxisType.Text
            'curPane.YAxis.Type = AxisType.Exponent
            mPane.Item(PaneIndex).XAxis.MajorGrid.IsVisible = True 'Сетка по X
            mPane.Item(PaneIndex).YAxis.MajorGrid.IsVisible = True 'Сетка по Y
            mPane.Item(PaneIndex).Legend.IsVisible = False
            mPane.Item(PaneIndex).YAxis.Scale.FontSpec.Size = 14

            mPane.Item(PaneIndex).Border.IsVisible = False



            mPane.Item(PaneIndex).BaseDimension = 4.0F

            mPane.Item(PaneIndex).Margin.All = 3
            mPane.Item(PaneIndex).Margin.Top = 8
            mPane.Item(PaneIndex).IsFontsScaled = False
            If PaneIndex = 0 Then
                SmallRect.X = 5
                SmallRect.Width = CalcPanewidth(AllElementsCount, mPane.Item(PaneIndex).CurveList.Item(0).Points.Count, mPane.Rect.Width) + 20

            ElseIf PaneIndex = mPane.PaneList.Count - 1 Then
                SmallRect.X = SmallRect.X + mPane.Item(PaneIndex - 1).Rect.Width
                SmallRect.Width = mPane.Rect.Width - SmallRect.X
                mPane.Item(PaneIndex).YAxis.MinSpace = 0
            Else
                SmallRect.X = SmallRect.X + mPane.Item(PaneIndex - 1).Rect.Width
                SmallRect.Width = CalcPanewidth(AllElementsCount, mPane.Item(PaneIndex).CurveList.Item(0).Points.Count, mPane.Rect.Width)
                mPane.Item(PaneIndex).YAxis.MinSpace = 0
            End If
            mPane.Item(PaneIndex).ReSize(CreateGraphics(), SmallRect)

        Next PaneIndex

        mPane.Legend.FontSpec.Size = 16

        mPane.BaseDimension = 12.0F
        mPane.Margin.Top = 22
        mPane.Margin.Left = 5
        mPane.Margin.Right = 35
        mPane.Margin.Bottom = 1
        mPane.Legend.Location.Height = mPane.Legend.Location.Height + 5
        mPane.Legend.Position = LegendPos.InsideTopRight
        mPane.Legend.FontSpec.Size = 25
        Dim r(0) As Integer

        mPane.IsFontsScaled = True

        'Это переопределяло размеры раньше
        'mPane.SetLayout(CreateGraphics(), PaneLayout.SingleRow)

        'Заполняем значениями

        Me.ZedGraphControl1.IsShowPointValues = True
        Me.ZedGraphControl1.AxisChange()
        Me.ZedGraphControl1.Invalidate()

Конечно часть кода вырезал но весь смысл в определении

 mPane.Item(PaneIndex).ReSize(CreateGraphics(), SmallRect)

Результат динамически настраиваемая ширина конечно код сырой но работает

Anton 19.12.2008 - 13:50

Вот фотки того что получилось

Jenyay 19.12.2008 - 14:13

Anton, а красиво смотрится :) Если Вы не против, то я сделаю на основе Вашего примера пример для шпаргалки.

Vardes 19.12.2008 - 22:24

Такой вопрос, как построить несколько графиков один под другим, не кидая на форму новых компонентов... Заранее спасибо...

Vardes 19.12.2008 - 23:28

Ещё возникли сложности: PointPairList работает только с типом double, возникает вопрос, как сделать,чтобы по оси Х располагались строковые переменные, а по оси Y double и именно в линейных графиках? К примеру Саша - 5 Коля - 8 Вася - 10...

Jenyay 20.12.2008 - 08:56

Vardes,

По поводу нескольких графиков - надо смотреть в сторону MasterPane, скоро я выложу пример такого использования.

А чтобы присвоить меткам на оси строковые значения есть свойство

Pane.XAxis.Scale.TextLabels

Только надо не забыть установить

Pane.XAxis.Type = AxisType.Text;

Anton 22.12.2008 - 07:18

Не жалко

"а красиво смотрится :) Если Вы не против, то я сделаю на основе Вашего примера пример для шпаргалки. "

Да пожалуйста пользуйся winking smiley

sWitch_2009 22.04.2009 - 10:24

Как изменить формат подписей

BarItem.CreateBarLabels(myPane, false, "f0"); Я так понимаю, f0 делает подписи типа int, цифры после запятой обрезаются. А мне надо... для типа double как это будет?

Jenyay 22.04.2009 - 10:31

To sWitch_2009:

На сколько я понял из документации (сам я эту фичу не использовал), последний параметр в CreateBarLabels использует те же строки форматирования, что и double.ToString(). "f0" как раз и означает дробные числа, но после запятой оставить 0 цифр, поэтому можно попробовать что-нибудь вроде "f3" и т.п.

sWitch_2009 23.04.2009 - 11:27

Большое спасибо!!!

Все гениальное просто!happy smiley

sWitch_2009 23.04.2009 - 12:10

Проблема с обновлением графиков

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

Jenyay 23.04.2009 - 19:35

Это уже надо смотреть на остальной код, так сходу что-то сказать трудно.

sWitch_2009 24.04.2009 - 12:09

Обновление графиков

Если взять хоть даже код с http://zedgraph.org/wiki/index.php?title=Multi-Colored_Bar_Demo для построения гистограммы, организовать загрузку диаграммы не сразу при загрузке формы, а по кнопке на этой форме, и в конце кода функции CreateGraph_GradientByZBars( ZedGraphControl z1 ) запросить ZedGraphControl.Invalidate();, то при повторном нажатии кнопки графики будут накладываться друг на друга.

Jenyay 24.04.2009 - 13:38

To sWitch_2009:

Он не наезжает, он просто создает каждый раз новые полоски для Bar. Чтобы этого не было, добавьте вторую строку:

GraphPane myPane = z1.GraphPane;
myPane.CurveList.Clear ();

sWitch_2009 27.04.2009 - 09:25

Спасибо большое!!!

Как хорошо, что вы тут есть!

Никита 12.05.2009 - 16:05

А можно ли найти точки пересечения

А можно ли найти точки пересечения двух Curve средствами самого Zedgraph?

barter 04.06.2009 - 08:35

отменить масштабирование шрифтов

не могу побороть вот это: если привязать контрол к форме и изменять размер формы, то в месте со всей графикой масштабируются и шрифты заголовков и подписей осей. подскажите как этого избежать плиз...

Malicious 10.06.2009 - 17:53

отображение промежутка

Здравствуйте. Моя программа отображает показания датчика в зависимости от его положения на прямой, данный поступают непрерывно. Мне необходимо чтобы отображался участок кривой с последними 500 значениями, как можно реализовать это? И еще как лучше организовать перерисовку кривой, если количество значений порядка 10 000 000, я предполагаю что каждый раз перерисовывать кривую будет очень медленно.

Jenyay 10.06.2009 - 20:05

Malicious, я бы не стал сваливать работу по отсечению лишних показаний на ZedGraph, а создал бы что-то вроде списка с конечной длиной, где бы хранились последние показания.

Malicious 11.06.2009 - 09:01

Спасибо за совет

Пробовал использовать Queue, но не получается отрисовать кривую, ZedGraph ругается на несоответствие типов. Как правильно это организовать - не знаю. Поэтому пока что использую способ Pane.XAxis.Scale.Min = x-500; Pane.XAxis.Scale.Max = x; Jenyay не могли бы вы подсказать как мне правильно использовать Queue

Jenyay 11.06.2009 - 09:32

Да, в принципе, и Queue можно использовать. Только нужно по одной точке добавлять в кривую графика. Примерно как это сделано в первом примере здесь.

Malicious 11.06.2009 - 10:35

Ни как не могу разобраться с Queue( Не могли бы вы привести кусочек такого кода для примера?

Jenyay 11.06.2009 - 17:55

Malicious, а создайте, пожалуйста, на форуме соответствующую тему. Просто здесь комментарии разрослись, уже неудобно что-то писать. Я ближе к вечеру постараюсь какой-нибудь пример сделать.

v567 18.06.2009 - 22:47

Проблемы быстрдействия ZedGraph

У меня вот какая проблема. Необходимо отображать точку в реальном режиме сразу же после ее поступления в программу. Для чистоты эксперимента слепил простенький тест с ZedGraph.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ZedGraph;

namespace Test
{
    public partial class TestForm : Form
    {
        public GraphPane myP;
        long m1, m2;
        LineItem mySerP;


        public TestForm()
        {
            InitializeComponent();
        }


        // Изменение ZedGraph с учетом изменения размеров формы
        private void SetSize()
        {
            zg6.Location = new Point(0, 0);
            zg6.Size = new Size(this.ClientRectangle.Width, this.ClientRectangle.Height);
            zg6.Refresh();
        }


        // Изменение размеров ФМ06
        private void F06_Resize(object sender, EventArgs e)
        {
            SetSize();         // Изменение размеров ZedGrpah
        }


        private void Form1_Shown(object sender, EventArgs e)
        {
            SetSize();                                                 // Изменение размеров ZedGrpah
            this.Move += new System.EventHandler(this.F06_Resize);
            this.Resize += new System.EventHandler(this.F06_Resize);
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            SetSize();

            myP = zg6.GraphPane;

            // Убираем всякий мусор (титлы и надписи по осям)
            myP.Title.FontSpec.Size = 6;
            myP.Title.Text = " ";           // резервируем поле сверху графика
            myP.XAxis.Title.Text = "";
            myP.YAxis.Title.Text = "";

            // Настройка шрифта осей
            myP.XAxis.Scale.FontSpec.Size = 9;
            myP.YAxis.Scale.FontSpec.Size = 9;
            myP.XAxis.Scale.FontSpec.IsBold = true;
            myP.YAxis.Scale.FontSpec.IsBold = true;

            // Градиентная заливка графика
            myP.Chart.Fill = new Fill(Color.White, Color.Gray, 45F);
            // Градиентная заливка коймы графика
            myP.Fill = new Fill(Color.White, Color.Gray, 45F);

            myP.XAxis.Scale.Min = 0;
            myP.XAxis.Scale.Max = 500;
            myP.YAxis.Scale.Min = 0;
            myP.YAxis.Scale.Max = 500;
            myP.AxisChange();               // перерисовка ZedGraph

            if (mySerP != null) mySerP.Clear();

            double[] XX = new double[1]; double[] YY = new double[1];
            XX[0] = 0; YY[0] = 0;
            mySerP = myP.AddCurve("", XX, YY, Color.DarkBlue);

            // Определяем серии измерений
            mySerP.Symbol.Type = SymbolType.Circle;
            // делаем линии соединяющие точки невидимыми
            mySerP.Line.IsVisible = false;
            // толщина линии 2 пикселя
            mySerP.Line.Width = 10;
            // точки в виде сплошных кругов
            mySerP.Symbol.Fill.Type = FillType.Solid;
            // определяем размер точек
            mySerP.Symbol.Size = 4;
        }


        private void Tm()
        {
            double r;

            m2 = DateTime.Now.Ticks;
            r = 0.0000001 * (m2 - m1);
            label1.Text = "Время выполнения= " + r.ToString("0.0") + "сек";
            zg6.Refresh();
            label1.Refresh();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            double x, y, Sg;

            m1 = DateTime.Now.Ticks;
            Sg = 0.0; x = 0.0;
            while (Sg < (12.0 * Math.PI))
            {
                y = 250.0  + (250.0 * Math.Sin(Sg));
                mySerP.AddPoint((int)(x), (int)(y));
                Sg += (0.5 * 6.0 * Math.PI) / 250.0;
                x += 0.5;

                Tm();
            }
        }
    }
}

Если производить отрисовку поточечно (как в указанном тесте), то тест выполняется слишком долго.

Можно ускорить его работу, например как в примере 2 (заменив Refresh() на Invalidate()),

private void Tm()
        {
            double r;

            m2 = DateTime.Now.Ticks;
            r = 0.0000001 * (m2 - m1);
            label1.Text = "Время выполнения= " + r.ToString("0.0") + "сек";
            //zg6.Refresh();
            zg6.Invalidate();
            label1.Refresh();
        }
 

либо как в примере 3 (перенеся Refresh() из Tm() в конец цикла отрисовки синусоиды.

private void button1_Click(object sender, EventArgs e)
        {
            double x, y, Sg;

            m1 = DateTime.Now.Ticks;
            Sg = 0.0; x = 0.0;
            while (Sg < (12.0 * Math.PI))
            {
                y = 250.0  + (250.0 * Math.Sin(Sg));
                mySerP.AddPoint((int)(x), (int)(y));
                Sg += (0.5 * 6.0 * Math.PI) / 250.0;
                x += 0.5;

                Tm();
            }
            zg6.Refresh();
            // либо zg6.Invalidate();
        }

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

Подскажите как можно решить данную проблему и существенно ускорить работу данного теста.

Jenyay 19.06.2009 - 10:40

v567, Вообще, если нужно рисовать точки последовательно, то лучше для этого использовать таймер, на каждый тик которого добавлять одну точку в список и выводить из все разом. Иначе при том сделано сейчас, скорость вывода точек будет зависеть от скорость компьютера, на котором выполняется программа.

v567 19.06.2009 - 13:18

Таймер не подходит, поскольку работает с определенной дискретностью. Задача же заключается в том, что необходимо мгновенно отобразить ассинхронно поступающие данные безо всяких задержек. В идеале нужно чтобы точка на графике отображалась сразу же после добавления (например так как это делает TChart в Delphi), а не после вызова Refresh (или связки Invalidate + Update), который обновляет всю область графика. Если брать TChart в Delphi, то команда Chart.Series.AddXY сразу же отображает точку на графике. Аналогичной в ZedGraph процедуре AddPoint для отображения точки почему то требуется дополнительный вызов Refresh. В результате TChart работает значительно быстрее, чем ZedGraph.

Так как на экране необходимо видеть точку сразу же после прихода данных возникает вопрос: как ускорить поточечную отрисовку в ZedGraph? Т.е. после прихода точку её нужно сразу же оторазить ничего не дожидаясь и не ожидая прихода других данных.

Jenyay 19.06.2009 - 13:31

А почему тогда нельзя сохранять все точки, которые нужно нарисовать, и рисовать их все разом? Когда появится новая точка, пользователю будет казаться, что они только что добавились, ведь старые останутся на месте.

v567 19.06.2009 - 14:34

Почему нельзя рисовать старые точки? Их можно рисовать хоть по десять проходов. Просто скорость отрисовки падает в разы. Одно дело одну точку нарисовать (предположительно как в TChart), а другое дело перерисовать всю область графика (как в Zedgraph после Refresh). Как бы там ни было, но аналогичный тест в delphi работает менее секунды zedgraph же пашет секунд 15.

Jenyay 19.06.2009 - 14:49

Значит я не правильно понял что требуется. Надо будет поиграться с Вашим примером.

v567 19.06.2009 - 15:22

Проект можно взять по адресу: http://linuxforum.ru/index.php?showtopic=90260

 23.06.2009 - 18:21

cool smiley

v567 24.06.2009 - 12:54

В поисках решения проблемы ускорения работы ZedGraph обнаружил интересную особенность метода Invalidate(): обновление производится после окончания работы потока его вызывающего. Для учета этой особенности изменил вышеуказанный тест, введя фоновый поток. В результате обновление производится корректно (именно так как надо, т.е. с помощью Invalidate() и при этом поточечно). Лучшая скорость работы теста с фоновым потоком составила 13.6 сек (старого - 15.4 сек). В связи с этим напрашивается вывод о том, что это и есть потолок быстродействия и библиотеки ZedGraph и платформы .NET в целом. Что в свою очередь означает, что быстродействие .NET значительно уступает быстродействию Win32. Напоминаю, что аналогичная поточечная отрисовка с помощью компонента TChart в Delphi занимает менее 1 секунды.

Текст теста с фоновым потоком:

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;
using System.Threading;
using ZedGraph;

namespace Test
{
    public partial class TestForm : Form
    {
        Thread FProc;
        public GraphPane myP;
        long m1, m2;
        LineItem mySerP;
        double x, y, Sg;


        public TestForm()
        {
            InitializeComponent();
            Vars.ObjTstF = this;
        }


        // Изменение ZedGraph с учетом изменения размеров формы
        private void SetSize()
        {
            zg6.Location = new Point(0, 0);
            zg6.Size = new Size(this.ClientRectangle.Width, this.ClientRectangle.Height);
            zg6.Refresh();
        }


        // Изменение размеров формы
        private void F06_Resize(object sender, EventArgs e)
        {
            SetSize();         // Изменение размеров ZedGrpah
        }


        private void Form1_Shown(object sender, EventArgs e)
        {
            SetSize();         // Изменение размеров ZedGrpah
            this.Move += new System.EventHandler(this.F06_Resize);
            this.Resize += new System.EventHandler(this.F06_Resize);
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            FProc = new Thread(FTimer.FonProc);

            SetSize();

            myP = zg6.GraphPane;

            // Убираем всякий мусор (титлы и надписи по осям)
            myP.Title.FontSpec.Size = 6;
            myP.Title.Text = " ";
            myP.XAxis.Title.Text = "";
            myP.YAxis.Title.Text = "";

            // Настройка шрифта осей
            myP.XAxis.Scale.FontSpec.Size = 9;
            myP.YAxis.Scale.FontSpec.Size = 9;
            myP.XAxis.Scale.FontSpec.IsBold = true;
            myP.YAxis.Scale.FontSpec.IsBold = true;

            // Градиентная заливка графика
            myP.Chart.Fill = new Fill(Color.White, Color.Gray, 45F);
            // Градиентная заливка коймы графика
            myP.Fill = new Fill(Color.White, Color.Gray, 45F);

            myP.XAxis.Scale.Min = 0;
            myP.XAxis.Scale.Max = 500;
            myP.YAxis.Scale.Min = 0;
            myP.YAxis.Scale.Max = 500;
            myP.AxisChange();              // перерисовка ZedGraph

            if (mySerP != null) mySerP.Clear();

            double[] XX = new double[1]; double[] YY = new double[1];
            XX[0] = 0; YY[0] = 0;
            mySerP = myP.AddCurve("", XX, YY, Color.DarkBlue);

            // Определяем параметры серии
            mySerP.Symbol.Type = SymbolType.Circle;
            mySerP.Line.IsVisible = false;
            mySerP.Line.Width = 10;
            mySerP.Symbol.Fill.Type = FillType.Solid;
            mySerP.Symbol.Size = 4;
        }


        // Процедура перерисовки графика
        public void Tm()
        {
            double r;

            if (this.InvokeRequired == false)   // наш поток ?
            {
                m2 = DateTime.Now.Ticks;
                r = 0.0000001 * (m2 - m1);
                label1.Text = "Время выполнения= " + r.ToString("0.0") + "сек";
                //zg6.Refresh();
                //label1.Refresh();
                zg6.Invalidate();
            }
            else                                // если не наш пускаем процедуру Invok'ом
            {
                DrawT FDraw = new DrawT(Tm);
                if (FProc != null) this.Invoke(FDraw);
            }
        }


        private void button1_Click(object sender, EventArgs e)
        {
            m1 = DateTime.Now.Ticks;
            Sg = 0.0; x = 0.0;

            // запускаем поток таймера
            Vars.PrTm = true;
            FProc.Start();
        }


        // Самодельный таймер вызываемый фоновым потоком
        public void timer()
        {
            Vars.S.PrRabs = true;

            if (Sg < (12.0 * Math.PI))
            {
                y = 250 + (int)(250.0 * Math.Sin(Sg));

                mySerP.AddPoint((int)(x), (int)(y));

                Sg += (0.5 * 6.0 * Math.PI) / 250.0;
                x += 0.5;

                Tm();
            }
            else
            {
                Vars.PrTm = false;
                if (FProc != null)
                {
                    Thread.Sleep(300);
                    FProc.Abort();
                }
            }

            Vars.S.PrRabs = false;
        }


        private void TestForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            Vars.PrTm = false;
            if (FProc != null)
            {
                Thread.Sleep(300);
                FProc.Abort();
            }
        }
    }


    // Делегат для решения проблем синхронизации потоков
    delegate void DrawT();


    // Класс с переменными общего доступа для всех потоков
    public class Vars
    {
        public static Vars S = new Vars();          // Собственный Class
        public static bool PrTm = false;
        public static TestForm ObjTstF = null;
        public bool PrRabs = false;
    }


    // фоновый поток таймера
    class FTimer
    {
        public static void FonProc()
        {
            while (Vars.PrTm)
            {
                Thread.Sleep(0);
                if (Vars.S.PrRabs == false)
                {
                    Vars.ObjTstF.timer();
                }
            }
        }
    }
}

v567 24.06.2009 - 13:12

Проект целиком кроме ссылки на linuxforum можно ещё взять здесь: http://www.cyberforum.ru/csharp-net/thread41029.html В указанной ссылке тест содержит текст (без фонового потока) который приводился ранее.

А с фоновым потоком выполнимый файл сделать труда не составит.

v567 24.06.2009 - 19:24

Решение найдено. happy smiley Как оказалось достаточно убрать в процедуре FTimer.FonProc() вызов Thread.Sleep(0). Время работы теста в этом случае составит 0.8 сек. Что более чем на порядок превосходит предыдущие результаты, но приблизительно в 4 раза хуже, чем в TChart'е. Однако это уже можно списать на медлительность .NET

Итак, итоговый вариант выглядит так happy smiley:

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;
using System.Threading;
using ZedGraph;

namespace Test
{
    public partial class TestForm : Form
    {
        Thread FProc;
        public GraphPane myP;
        long m1, m2;
        LineItem mySerP;
        double x, y, Sg;


        public TestForm()
        {
            InitializeComponent();
            Vars.ObjTstF = this;
        }


        // Изменение ZedGraph с учетом изменения размеров формы
        private void SetSize()
        {
            zg6.Location = new Point(0, 0);
            zg6.Size = new Size(this.ClientRectangle.Width, this.ClientRectangle.Height);
            zg6.Refresh();
        }


        // Изменение размеров формы
        private void F06_Resize(object sender, EventArgs e)
        {
            SetSize();         // Изменение размеров ZedGrpah
        }


        private void Form1_Shown(object sender, EventArgs e)
        {
            SetSize();         // Изменение размеров ZedGrpah
            this.Move += new System.EventHandler(this.F06_Resize);
            this.Resize += new System.EventHandler(this.F06_Resize);
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            FProc = new Thread(FTimer.FonProc);

            SetSize();

            myP = zg6.GraphPane;

            // Убираем всякий мусор (титлы и надписи по осям)
            myP.Title.FontSpec.Size = 6;
            myP.Title.Text = " ";
            myP.XAxis.Title.Text = "";
            myP.YAxis.Title.Text = "";

            // Настройка шрифта осей
            myP.XAxis.Scale.FontSpec.Size = 9;
            myP.YAxis.Scale.FontSpec.Size = 9;
            myP.XAxis.Scale.FontSpec.IsBold = true;
            myP.YAxis.Scale.FontSpec.IsBold = true;

            // Градиентная заливка графика
            myP.Chart.Fill = new Fill(Color.White, Color.Gray, 45F);
            // Градиентная заливка коймы графика
            myP.Fill = new Fill(Color.White, Color.Gray, 45F);

            myP.XAxis.Scale.Min = 0;
            myP.XAxis.Scale.Max = 500;
            myP.YAxis.Scale.Min = 0;
            myP.YAxis.Scale.Max = 500;
            myP.AxisChange();              // перерисовка ZedGraph

            if (mySerP != null) mySerP.Clear();

            double[] XX = new double[1]; double[] YY = new double[1];
            XX[0] = 0; YY[0] = 0;
            mySerP = myP.AddCurve("", XX, YY, Color.DarkBlue);

            // Определяем параметры серии
            mySerP.Symbol.Type = SymbolType.Circle;
            mySerP.Line.IsVisible = false;
            mySerP.Line.Width = 10;
            mySerP.Symbol.Fill.Type = FillType.Solid;
            mySerP.Symbol.Size = 4;
        }


        // Процедура перерисовки графика
        public void Tm()
        {
            double r;

            if (this.InvokeRequired == false)   // наш поток ?
            {
                m2 = DateTime.Now.Ticks;
                r = 0.0000001 * (m2 - m1);
                label1.Text = "Время выполнения= " + r.ToString("0.0") + "сек";
                //zg6.Refresh();
                //label1.Refresh();
                zg6.Invalidate();
            }
            else                                // если не наш пускаем процедуру Invok'ом
            {
                DrawT FDraw = new DrawT(Tm);
                if (FProc != null) this.Invoke(FDraw);
            }
        }


        private void button1_Click(object sender, EventArgs e)
        {
            m1 = DateTime.Now.Ticks;
            Sg = 0.0; x = 0.0;

            // запускаем поток таймера
            Vars.PrTm = true;
            FProc.Start();
        }


        // Самодельный таймер вызываемый фоновым потоком
        public void timer()
        {
            Vars.S.PrRabs = true;

            if (Sg < (12.0 * Math.PI))
            {
                y = 250 + (int)(250.0 * Math.Sin(Sg));

                mySerP.AddPoint((int)(x), (int)(y));

                Sg += (0.5 * 6.0 * Math.PI) / 250.0;
                x += 0.5;

                Tm();
            }
            else
            {
                Vars.PrTm = false;
                if (FProc != null)
                {
                    Thread.Sleep(300);
                    FProc.Abort();
                }
            }

            Vars.S.PrRabs = false;
        }


        private void TestForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            Vars.PrTm = false;
            if (FProc != null)
            {
                Thread.Sleep(300);
                FProc.Abort();
            }
        }
    }


    // Делегат для решения проблем синхронизации потоков
    delegate void DrawT();


    // Класс с переменными общего доступа для всех потоков
    public class Vars
    {
        public static Vars S = new Vars();          // Собственный Class
        public static bool PrTm = false;
        public static TestForm ObjTstF = null;
        public bool PrRabs = false;
    }


    // фоновый поток таймера
    class FTimer
    {
        public static void FonProc()
        {
            while (Vars.PrTm)
            {
                // Thread.Sleep(0);
                if (Vars.S.PrRabs == false)
                {
                    Vars.ObjTstF.timer();
                }
            }
        }
    }
}

hoplin 31.08.2009 - 08:45

спасибо за материалы. пользуемся )

Рутакате 09.10.2009 - 23:10

Как сдвинуть столбцы

Точнее-как сделать так,чтобы при построении Bar-а,столбцы стояли вплотную друг к другу?Оч срочно!!!))

Jenyay 09.10.2009 - 23:18

Рутакате, гляньте этот класс

graber 22.10.2009 - 19:21

преобразование координат

столкнулся с такой проблемой: мне надо, чтобы при движении курсора мыши по графику, выводились координаты курсора в этом графике. как преобразовать экранные координаты к координатам графика. соответственно при выходе курсора за границы графика, считывание координат должно прекратиться. график лежит в определенных интервалах и не масштабируется.

Jenyay 22.10.2009 - 21:37

@CintaNotes,

Что-то похожее в ZedGraph есть. Как будет время, покопаюсь.

graber 22.10.2009 - 22:33

Re:преобразование координат

нашел, все работает. может кому поможет, вот код: private bool zedGraphControl1_MouseMoveEvent( ZedGraphControl sender, MouseEventArgs e ) {

   // Save the mouse location
   PointF mousePt = new PointF( e.X, e.Y );

   // Find the Chart rect that contains the current mouse location
   GraphPane pane = sender.MasterPane.FindChartRect( mousePt );

   // If pane is non-null, we have a valid location.  Otherwise, the mouse is not
   // within any chart rect.
   if ( pane != null )
   {
      double x, y;
      // Convert the mouse location to X, and Y scale values
      pane.ReverseTransform( mousePt, out x, out y );
      // Format the status label text
      toolStripStatusXY.Text = "(" + x.ToString("f2") + ", " + y.ToString("f2") + ")";
   }
   else
      // If there is no valid data, then clear the status label text
      toolStripStatusXY.Text = string.Empty;

   // Return false to indicate we have not processed the MouseMoveEvent
   // ZedGraphControl should still go ahead and handle it
   return false;

}

и ссылка на источник: http://zedgraph.org/wiki/index.php?title=Show_the__Cursor_Location_in_a_Status_bar

zaqazaqaz 16.11.2009 - 13:27

ПОМОГИТЕ ПЖЛ!!!!!!!

у меня построен график подскажите ПЖЛ как сделать такое : по mouseclick, получать координаты точки на которую кликаю а не координаты формы., ну или просто координаты места на графике. ПЖЛ ПЖЛ ПЖЛ ПЖЛ ПЖЛ ПЖЛ ПЖЛ ПЖЛ ПОМОГИТЕ ПОМОГИТЕ ПОМОГИТЕ ПОМОГИТЕ ПОМОГИТЕ ПОМОГИТЕ ПОМОГИТЕ ПОМОГИТЕ ПОМОГИТЕ

Jenyay 16.11.2009 - 21:30

zaqazaqaz, посмотрите комментарий выше. Попозже постараюсь сделать подобный пример.

Серж 19.12.2009 - 16:43

Была раньше. Точка пересечения двух прямых.

Только вливаюсь в ваши ряды. Вот сразу вопрос - как получить точку пересечения двух Curve?

Ффф 27.01.2010 - 00:20

Можно ли отключить контекстное меню, которое вылезает по нажатию правой кнопкой мыши на графике?

Jenyay 27.01.2010 - 09:25

Ффф, можно. Для этого надо установить свойство IsShowContextMenu в false.

Артем 03.03.2010 - 04:51

Подскажите пожалуйста, как получить доступ к параметрам уже построенной кривой. т.е один из методов в моей программе строит график какой то функции, а другой метод каким то образом этот график должен преобразовать, т.е мне необходимо получить во втором методе вектора точек по которым строился начальный график, переменную типа lineItem общую для всех методов класса вводить не хочется, так как в ней будет, последняя построенная функция, а мне надо иметь доступ к любой функции построенной на graphpane. Как мнее получать параметры любой построенной функции по индексу?

Jenyay 03.03.2010 - 17:27

У класса GraphPane есть свойство CurveList - список кривых. Если я правильно понял, то это то, что Вам нужно.

Jenyay 03.03.2010 - 19:20

Добавил новый пример про изменение кривых.

Алена 12.03.2010 - 23:35

Формат меток осей

Сначала хочу поблагодарить за то, что вы нам помогаете! С помощью вашего ресурса снимается сразу масса вопросов. Однако не нашла решения для моей проблемки: по оси Y откладываются шестизначные цифры (140233, 140234, 140234 и т.д.), но на самой оси они отражаются как "140,2" при этом название оси выглядит так "Y Axis (10^3)". Понятно, что он из лучших побуждений сокращает мои большие цифры, но они мне нужны полноценные. Подскажите, где можно выставить нормальное отображение цифр?

Jenyay 13.03.2010 - 16:53

Алена, я тоже недавно столкнулся с такой проблемой, еще не искал как ее обойти. Если найду, то обязательно напишу.

Jenyay 14.03.2010 - 19:25

Алена, добавил пример по Вашему вопросу.

Алена 14.03.2010 - 22:20

Спасибо огромное!!! Сама бы еще не скоро не догадалась)

Править - История - Печать - Последние изменения - Поиск
Последняя редакция от 14.03.2010 22:20