Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > Класс


Автор: Franz1981 8.10.2008, 16:04
В общем необходимо при изменении положения скролбара нарисовать прямую. Создаю объект Ер класса  EpPos, и тутже вызываю  Ep.Pos(), которая и должна нарисовать, но ничего не происходит;

Код

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;

namespace WindowsFormsApplication1
{ 
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
             
        }

        private void Form1_Activated(object sender, EventArgs e)
        {
           
        }

        private void hScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            EpPos Ep = new EpPos();
            Ep.Pos();
        }
    }


    public class EpPos:WindowsFormsApplication1.Form1
    {
        public void Pos()
        {
            int[] Point1=new int[2];
            int [] Point2 = new int[2];
       
            
            Point1[0] = pictureBox2.Width / 2 - hScrollBar1.Value; //T1
            Point1[1] = pictureBox2.Height / 2 + hScrollBar2.Value;

            Point2[0] = pictureBox2.Width / 2 - hScrollBar1.Value; //koordinaty T2  
            Point2[1] = pictureBox2.Height / 2 + hScrollBar3.Value;

            DrawEp(Point1, Point2);


        }
        void DrawEp(int [] Point1, int [] Point2)
        {
            System.Drawing.Pen myPen;
            myPen = new System.Drawing.Pen(System.Drawing.Color.Red);
            System.Drawing.Graphics formGraphics = pictureBox2.CreateGraphics();
            formGraphics.DrawLine(myPen, 21, 1, 200, 200);
            myPen.Dispose();
            formGraphics.Dispose();

        }
    }



}


Автор: diadiavova 8.10.2008, 21:29
В саму логику прорисовки я не вчитывался, но что не правильно в остальном объясню. Тебе методы надо было в основной форме создавать, а ты вместо этого создаёшь производную от неё причём каждый раз при возникновении события. И вызываешь эти методы у второй формы(даже не запуская её, хотя этого делать ьочно не стоит)

Код

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;
namespace WindowsFormsApplication1
{ 
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
             
        }

        private void hScrollBar1_ValueChanged(object sender, EventArgs e)
        {
                Pos();
        }

                public void Pos()
        {
            int[] Point1=new int[2];
            int [] Point2 = new int[2];
       
            
            Point1[0] = pictureBox2.Width / 2 - hScrollBar1.Value; //T1
            Point1[1] = pictureBox2.Height / 2 + hScrollBar2.Value;
            Point2[0] = pictureBox2.Width / 2 - hScrollBar1.Value; //koordinaty T2  
            Point2[1] = pictureBox2.Height / 2 + hScrollBar3.Value;
            DrawEp(Point1, Point2);
        }
        void DrawEp(int [] Point1, int [] Point2)
        {
            System.Drawing.Pen myPen;
            myPen = new System.Drawing.Pen(System.Drawing.Color.Red);
            System.Drawing.Graphics formGraphics = pictureBox2.CreateGraphics();
            formGraphics.DrawLine(myPen, 21, 1, 200, 200);
            myPen.Dispose();
            formGraphics.Dispose();
        }
    }
   
}


То, что явно не правильно я исправил(не проверял), если будет другая ерунда - пиши.

Автор: Ctrl 9.10.2008, 01:39
Заниматься прямым рисованием при изменении каких-то факторов - это не есть хорошо, ибо
нарисованное тобой пропадет при первом же чихе, да и к тому же, если отрисовка нетривиальная,
перфоманс здорово просядет. Ну и плюс куча других менее очевидных причин...

Нормальный сценарий - это изменение свойств[0] т.н. модели [1]
(класс или группа классов, описывающих некие состояния и связанную с ними логику) 
и подача уведомления [2] об изменении модели в т.н. представление [3]
(класс или группа классов анимающихся отображением UI или связанными с этим вещами) 
а уж оно(представление) и должно обеспечить отрисовку[4]

Вот простой пример:
 (на форме горизонтальный и вертикальный скроллы, при изменении значения любого скролла
  считается некие процентные значения (Model) , 
 которые отображаются в виде положения 2D точки на пересечении линий (View) )

Код

using System;
using System.Drawing;
using System.Windows.Forms;

namespace PaintTestApp {
    public partial class TestForm : Form {
        View viewCore;
        Model modelCore;

        //
        public TestForm() {
            InitializeComponent();

            this.modelCore = CreateModel();
            this.viewCore = CreateView(Model);
            
            this.Controls.Add(View);
            View.Bounds = new Rectangle(10, 10, 250, 200);

            hScroll.ValueChanged += OnHScrollValueChanged;
            vScroll.ValueChanged += OnVScrollValueChanged;
            hScroll.Value = 50; // let be from 0 to 100
            vScroll.Value = 50; // let be from 0 to 100
        }
        protected Model Model {
            get { return modelCore; }
        }
        protected View View {
            get { return viewCore; }
        }
        protected virtual Model CreateModel() {
            return new Model();
        }
        protected virtual View CreateView(Model m) {
            return new View(m);
        }
        void OnHScrollValueChanged(object sender, EventArgs e) {
            Model.HorzFactor = (float)hScroll.Value / (float)(hScroll.Maximum - hScroll.Minimum);
        }
        void OnVScrollValueChanged(object sender, EventArgs e) {
            Model.VertFactor = (float)vScroll.Value / (float)(vScroll.Maximum - vScroll.Minimum);
        }
    }
    public class Model { //[1]
        float hFactorCore;
        float vFactorCore;
        public float HorzFactor {
            get { return hFactorCore; }
            set {
                if (hFactorCore == value) return;
                hFactorCore = value; //[0]
                OnModelChanged();
            }
        }
        public float VertFactor {
            get { return vFactorCore; }
            set {
                if (vFactorCore == value) return;
                vFactorCore = value; //[0]
                OnModelChanged();
            }
        }
        public event EventHandler Changed;
        protected void OnModelChanged() {
            if (Changed != null) Changed(this, EventArgs.Empty); //[2]
        }
    }
    public class View : Control { //[3]
        Model modelCore;
        public View(Model model) {
            this.modelCore = model;
            Model.Changed += OnModelChanged; //  [2]
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
        }
        void OnModelChanged(object sender, EventArgs e) {
            Invalidate();
        }
        protected Model Model {
            get { return modelCore; }
        }
        protected override void OnPaintBackground(PaintEventArgs pevent) {
            pevent.Graphics.Clear(Color.White);
        }
        protected override void OnPaint(PaintEventArgs e) { //[4]
            PointF pt = new PointF(
                    (float)Model.HorzFactor * (float)Width,
                    (float)Model.VertFactor * (float)Height
                );
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            e.Graphics.DrawLine(Pens.Gainsboro, pt.X, 0f, pt.X, (float)Height);
            e.Graphics.DrawLine(Pens.Gainsboro, 0f, pt.Y, (float)Width, pt.Y);
            e.Graphics.FillEllipse(Brushes.Red, pt.X-3f, pt.Y-3f, 6f, 6f);
            e.Graphics.DrawRectangle(Pens.Black, 0, 0, Width, Height);
        }
    }
}

p.s. возможно я и отклонился от темы, 
но в примере как раз показано, где  и как надо рисовать

Автор: diadiavova 9.10.2008, 10:07
Извини, но я покачто мысли читать не научился(работаю над этим), перечитай своё первое сообщение и попробуй найти там всё о чём ты пишешь во втором. 
Для того, чтобы графика на пропадала "при каждом чихе" её надо отрисовывать всякий раз пр прорисовке формы (или другого контрола), в примере, который ты выложил во втором сообщении сделано именно так. Там картинка отрисовывается в методе OnPaint. Кроме того в твоём примере во-первых прорисовке ведётся в контроле(а не в новой форме), а во-вторых контрол не создаётся каждый раз заново. Поэтому всё происходит в одном контроле а не в разных, да и контрол размещается на форме, а не как у тебя создаётся и всё.
Что касается изменения состояния(о котором в первом сообщении я тоже не нашёл ни слова) изложи задачу яснее. В общем случае для прорисовки нужно пользоваться не числами, а значениями свойств объекта, которые могут меняться, но опять-таки вместо того, чтобы описать, что тебе надо, ты привёл пример не имеющий(как я понимаю) отношения к твоей задаче.
Если же говорить о твоём первом премере, то , извини, но там херня полная, потомучто ты содаёшь в базовом классе экземпляры производного, а он как известно наследет функциональльность предка, то есть это тоже форма, которая будет при изменении состояния скролбара создавать такие же формы. Просто ты забыл запустить эту форму(и хорошо, что забыл). 
Если же тебе нужно, чтобы состояние изображения поддерживалось другим объектом, то и создавай для этого, специальный класс, и в алгоритме прорисовки ипользуй данные из него, тоько не надо производить его от самой формы. А давать более конкретные советы с примерами я не могу пока ты не изложил задачу.

Автор: Ctrl 9.10.2008, 10:36
2 diadiavova:
Немного непонятна причина твоих нападок - один человек (Franz1981) спросил как и где ему 
лучше что то отрисовать, привел свой пример. 
Другой человек (Ctrl) посмотрел его пример, прикинул что тот пытается сделать и где могут быть проблемы,
и в ответ набросал свой пример на похожую тему. Причем тут чтение мыслей?
Моей мотивацией было лишь желание поделиться опытом и помочь новичку меньше наступать на грабли...

С уважением, Ctrl

Автор: diadiavova 9.10.2008, 10:47
Не обращай много внимания на форму изложения, я и не думал ни о каких нападках, но просто когда ты задаёшь один вопрос, а получив на него ответ выкладываешь целый философический трактат (с употреблением слов типа "нетривиальный"), общий смысл которого в том, что я написал хрень, то я не знаю как ещё реагировать. А если некоторые обороты показались тебе резкими - извини.
А задачу всё-таки надо формулировать ясней, это я не в качестве очередной нападки, а просто совет, который поможет получить ясный ответ. Просмотри материалы форума и ты увидишь, что большинство вопросов, оставшихся без ответа, просто непонятно сформулированы. А на мой стиль не обращай внимания.
С ничуть не меньшим уважением, diadiavova.

Автор: diadiavova 9.10.2008, 11:59
Ctrl, До меня только сейчас дошло, что я разговаривал с двумя разным людьми. Извиняюсь, пропёрся. smile 

Автор: Franz1981 9.10.2008, 13:18
diadiavova, 
Ctrl, Огромное вам спасибо!)

Автор: Franz1981 9.10.2008, 14:34
Итак возник новый вопрос. Вот я отдельно создал класс

Код

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WindowsFormsApplication1
{
    public class Epur:Form1
    {
        public void Pos()
        {
            int[] Point1 = new int[2];
            int[] Point2 = new int[2];
            int[] Point3 = new int[2];

            Point1[0] = pictureBox2.Width / 2 - hScrollBar1.Value; //T1
            Point1[1] = pictureBox2.Height / 2 + hScrollBar2.Value;

            Point2[0] = pictureBox2.Width / 2 - hScrollBar1.Value; //koordinaty T2  
            Point2[1] = pictureBox2.Height / 2 + hScrollBar3.Value;
         
            DrawEp(Point1, Point2);


        }

        public void DrawEp()
        {
            System.Drawing.Pen myPen;
            myPen = new System.Drawing.Pen(System.Drawing.Color.Red);
            System.Drawing.Graphics formGraphics = pictureBox2.CreateGraphics();
            formGraphics.DrawLine(myPen, 21, 1, 200, 200);
            myPen.Dispose();
            formGraphics.Dispose();
        }
    }
}


Вот и вопрос в следующем: в какой части кода(нижеприведённого) мне необходимо объявить создание экземпляра? чтобы методы класса были доступны для, например, событий
Основой упор я сейчас делаю на понимание принципа работы класса, рисование ,пока, второстепенно.

Код

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;

namespace WindowsFormsApplication1
{      public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            
 
        }

        private void Form1_Activated(object sender, EventArgs e)
        {
           
        }

        private void hScrollBar1_ValueChanged(object sender, EventArgs e)
        {
           
        }
    }


   
    }



Автор: diadiavova 9.10.2008, 14:48
Это зависит от того, для чего тебе это надо. Но в любом случае конструкция опасная, может привести(при неправильном использованиии) к бесконечному рекурсивному вызову.
Представь себе, что всё, что ты сейчас напишешь, так же окажется и в классе Epur, включая создание нового экземпляра. То есть, в базовом классе, ты создаёшь экземпляр производного, тот в свою очередь наследует эту функциональность и так же создаёт очередной экземпляр, дальше всё работает по принципу 
Цитата

Чтобы понять рекурсию, сначала надо понять рекурсию.

Если ты более понятно обрисуешь что тебе надо, то можно будет решить проблему. 
Тебе надо понять, что класс Epur - тоже форма, и в ней есть всё, что и в Form1. В этом суть наследования.
Опиши, что тебе надо. Прорисовка в самой форме, или создание другой. И если последнее, то зачем ты производишь её от вызывающей формы


Цитата(Franz1981 @  9.10.2008,  14:34 Найти цитируемый пост)
public class Epur:Form1

Вот это зачем нужно?

Автор: diadiavova 9.10.2008, 15:09
Если я непонятно объяснил - проведи такой эксперимент
Код

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;
namespace WindowsFormsApplication1
{      public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Epur ep = new Epur();
            ep.Show();
          
        }
        private void Form1_Activated(object sender, EventArgs e)
        {
           
        }
        private void hScrollBar1_ValueChanged(object sender, EventArgs e)
        {
           
        }
    }
   
    }


Понимаю, "спасибо" за этот код ты не скажешь, но по крайней мере поймёшь, о чём я толкую. 

Автор: Franz1981 9.10.2008, 15:37
цель наследования - получить доступ к объектам формы..ерунда да?)

а вот насчёт последнего примера, я так и делал, только в какихто случаях компиляция происходила с ошибкой а в других просто не работало ничего.

Автор: diadiavova 9.10.2008, 16:10
Если бы ты так и сделал, у тебя при запуске формы начали бы создаваться и вызываться всё новые формы пока не произошло бы переполнение стэка, о чём тебя уведомило бы окно сообщений.

Наследование влечёт за собой не только доступ, но и получение всей функциональности базового класса оптом(за исключением тех функций, которые спрятаны от наследников, но и они могут делать своё чёрное дело). Для получения доступа есть масса других способов. 
Определение модификаторов области видимости(private, public и т.д.) - самый простой путь. Получить доступ к public членам можно откуда угодно, можно метод сделать видимым только для производных классов(protected), или например только для тех, которые определены в той же сборке(извиняюсь - как это на сишарпе не знаю, в VBNet это Friend), так что если дело только в этом, то наследование тут не причём, потомучто, доступными только для наследников являются только члены описанные как protected.
 Если не подходит - тут надо смотреть по задаче, я поэтому и говорю, что пока не ясен диагноз, трудно назначить лечение.
Но в любом случае надо понимать, что экземпляр производного класса, является так же экземпляром базового класса, и наследует его поведение. Если в Form1 ты выполняешь какое-либо действие, это означает, что в Epur оно тоже будет выполняться, поэтому, создавая экземпляр Epur в Form1, ты по сути создаёшь ещё одну такую же форму(которая будет вести себя так же), только с некоторыми дополнительными элементами поведения. Но она тоже будет создавать очередной экземпляр, и с ним произойдёт то же самое. В некоторых случаях подобная логика нужна, но если этот процесс не контролируется - это приводит к переполнению стэка.
Я ещё раз повторяю: Опиши задачу.
Твой вопрос

Цитата(Franz1981 @  9.10.2008,  14:34 Найти цитируемый пост)
в какой части кода(нижеприведённого) мне необходимо объявить создание экземпляра?

это всё равно, что я спросил бы
Цитата

Что-то мне не здровится, какую таблэтку выпить?


Автор: Franz1981 10.10.2008, 09:33
я хочу, чтобы был отдельно класс, максимально выполняющий поставленную задачу, чтобы в основном коде были только вызовы функций, вот.  Сейчас пробовал класс не наследовать от Form1, скролбары сделал public, но почемуто доступ из класса к ним получить никак не могу.

Автор: diadiavova 10.10.2008, 10:02
Покажи как ты сделал, я объясню, что не правильно.

Добавлено через 2 минуты и 25 секунд
Покажи как ты сделал, я объясню, что не правильно.

Автор: Franz1981 10.10.2008, 10:39
взял из соседней темы класс:

Код

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace WindowsFormsApplication1
{

    class MyClass
    {
        Form1 parentFrm;
        public void foo()
        {
            parentFrm.pictureBox1.Height = 10 ;
            
        }
        
        public MyClass(Form1 frm)
        {
            parentFrm = frm;
        }
    }
}


и 
Код


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;

namespace WindowsFormsApplication1
{      public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            MyClass c = new MyClass(this);
            
 
        }

        private void Form1_Activated(object sender, EventArgs e)
        {
           
        }

        public void hScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            c.foo();
        }
    }


   
    }






не очень понятны некоторые моменты в описании методов класса, и ещё когда вот создаю экземпляр "с", он недоступен из   
Код

public void hScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            c.foo();
        }

Автор: diadiavova 10.10.2008, 11:47
Покажи как ты сделал, я объясню, что не правильно.

Автор: Franz1981 10.10.2008, 12:33
вобщем остался только один вопрос:

Цитата

не очень понятны некоторые моменты в описании методов класса, и ещё когда вот создаю экземпляр "с", он недоступен из  

Код

public void hScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            c.foo();
        }


Автор: diadiavova 10.10.2008, 12:42
Переменную надо создавать на уровне класса, а в методе при создании экземпляра передавать его этой переменной. Доступ к объекту можно получить через переменную.

Код

public class aaa
{
    public aaa()
    {
        f = new MyForm();
    }
    MyForm f;
}

public class MyForm:Form
{}


В этом случае обратиться к полю f экземпляра aaa можно откуда угодно, а инициируется оно в конструкторе.

Автор: Franz1981 10.10.2008, 13:00
не понял smile  можно поподробней? smile 

Автор: mihryak 10.10.2008, 13:02
может книжку всё же? ;)

Автор: diadiavova 10.10.2008, 13:11

Вот так сделано у тебя
 
Код

  public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            MyClass c = new MyClass(this);
            
 
        }
        private void Form1_Activated(object sender, EventArgs e)
        {
           
        }
        public void hScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            c.foo();
        }
    }



А вот так надо 
Код

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            c = new MyClass(this);
            
 
        }
         public MyClass c;
        private void Form1_Activated(object sender, EventArgs e)
        {
           
        }
        public void hScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            c.foo();
        }
    }




Цитата(mihryak @  10.10.2008,  13:02 Найти цитируемый пост)
может книжку всё же? ;) 

Книжка - дело хорошее, и самао собой надо, только вот ведь в чём беда, если в книжке чего не понятно - никто разжёвывать не будет. А поскольку книжки пишут профессионалы, им иногда кажется тема лёгкой и не требующей дополнительных разъяснений, а новичку не понятно. Для того и существуют форумы.

Автор: Franz1981 10.10.2008, 13:22
Большое спасибо, diadiavova!! smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)