На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: maxim84_
  
> Использование функций GDI(API) , при отсутствии аналогов в GDI+
    С osa обсуждали довольно долго эту тему, отдельное ему спасибо, за то что подкинул интересную идею.
    Функия SetROP2 позволяет рисовать инверсным пером, что может пригодиться в том случае, если требуется быстро рисовать несложную движущуюся фигурку поверх какого-нибудь сложного, «тяжелого» рисунка. Т.е. если таким пером нарисовать линию, то по этой линии черное станет белым, белое черным и т.д. Значит не нужно перерисовывать всю картинку, для удаления линии, а достаточно нарисовать ее второй раз по этому же месту. Получается достаточно эффектно и без неприятного мерцания всей картинки. К сожалению, мне так и не удалось установить ROP2 для объекта Graphics, а потом рисовать средствами GDI+. Т.е. мы рисуем либо с помощью GDI, либо с помощью GDI+. Совмещать не получается. Поэтому необходимо декларировать не только функцию SetROP2, но так же и остальные функции GDI, с помощью которых предполагается рисовать. В данном примере это простейший набор, содержащий: CreatePen, SelectObject, DeleteObject, MoveToEx, LineTo и собственно SetROP2.

    Для получения возможности вызова функции API должно быть подключено пространство имен InteropServices:
    ExpandedWrap disabled
      uses System.Runtime.InteropServices;


    Дальше декларируем функции:
    ExpandedWrap disabled
      [DllImport("gdi32",CharSet=CharSet.None)]
      public static extern System.IntPtr CreatePen(int PenStyle,int Width,int color);
       
      [DllImport("gdi32",CharSet=CharSet.None)]
      public static extern System.IntPtr SelectObject(System.IntPtr hdc,System.IntPtr hgdiobj);
       
      [DllImport("gdi32",CharSet=CharSet.None)]
      public static extern void DeleteObject(System.IntPtr hdc,System.IntPtr hgdiobj);
       
      [DllImport("gdi32",CharSet=CharSet.None)]                      
      public static extern void MoveToEx(System.IntPtr hdc,int x, int y,System.IntPtr tufta);
              
      [DllImport("gdi32",CharSet=CharSet.None)]
      public static extern void LineTo(System.IntPtr hdc,int x, int y);
              
      [DllImport("gdi32.dll",CharSet=CharSet.None)]
      public static extern int SetROP2(System.IntPtr hdc,int mode);


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

    ExpandedWrap disabled
      int LastMouseTop=-1000;


    Рисовать будем в PictureBox-e, чтобы не заморачиваться на рисование в обработчике Form1_Paint(..., а в качестве фона, для примера, возьмем какой-нибудь достаточно большой растровый рисунок из файла (о наличии такого файла, и PictureBox-а на форме позаботьтесь сами :)).

    ExpandedWrap disabled
      public Form1()
      {
          InitializeComponent();
          //Загрузим тяжелую картинку
          pictureBox1.Image=(Bitmap)Image.FromFile("d:\\bigfile.jpg");
      }
              
       
      private void pictureBox1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
      {
          //для начала возьмем Graphics
          Graphics grf=this.pictureBox1.CreateGraphics();
       
          //но для GDI Graphics не указ - нужно получить HDC
          //такой тип в .net отсутствует поеэтому берем System.IntPtr - аналог void* из си.
          System.IntPtr hdc=grf.GetHdc();
       
          //Объект GDI HPEN - также отсутсвует
          //опять IntPtr,
          //кстати чтобы им рисовать его нужно создать
          const int PS_SOLID=0; //аналог сишных деклараций(подробно - смотрите MSDN и изучайте си)
          System.IntPtr pen=CreatePen(PS_SOLID,2,0);
       
          //Перо мало создать - его надо еще и выбрать, сохранив какое-то,
          //неважно какое, предыдущее перо
          System.IntPtr OldPen=SelectObject(hdc,pen);
                  
          //Добрались таки
          SetROP2(hdc,6);
       
          //Функция MoveToEx третьим параметром требует указатель куда будет записано
          // положение структуры POINT содержащую инфу о предыдущем положении указателя
          // рисования - нам не надо
              IntPtr tufta=(IntPtr)0;
          MoveToEx(hdc,0,LastMouseTop,tufta);//устанавливаем начало линии
          LineTo(hdc,pictureBox1.Image.Width,LastMouseTop);//и рисуем до конца - нарисовали на старом месте
       
          //сохраним новые координаты
          LastMouseTop=e.Y;
       
          //и нарисуем на новом месте
          MoveToEx(hdc,0,e.Y,tufta);
          LineTo(hdc,pictureBox1.Image.Width,e.Y);
       
          //Здесь вам не .NET! Если уж чего взял , так
          //ПОЛОЖИ НА МЕСТО!
          SelectObject(hdc,OldPen);//устанавливаем старый пен
          DeleteObject(hdc,pen);//удаляем тот что мы создали
          grf.ReleaseHdc(hdc);//освобождаем HDC
                                  
          grf.Dispose();//графикс тоже не нужен
      }
      для рисования инверсных линий, если они горизонтальные или вертикальные не обязательно использовать API. Можно воспользоваться методами класса ControlPaint. Вот пример рисования рамки на PictureBox который находится на форме:
      ExpandedWrap disabled
                bool _drawFrame = false;
                Rectangle _rect1;
                private void Form1_Load(object sender, EventArgs e)
                {
                    pictureBox1.MouseDown += new MouseEventHandler(pictureBox1_MouseDown);
                    pictureBox1.MouseMove += new MouseEventHandler(pictureBox1_MouseMove);
                    pictureBox1.MouseUp += new MouseEventHandler(pictureBox1_MouseUp);
                    pictureBox1.MouseLeave += new EventHandler(pictureBox1_MouseLeave);
                }
         
                void EndPaintFrame()
                {
                    if (_drawFrame)
                    {
                        _drawFrame = false;
                        //затираем рамку
                        ControlPaint.DrawReversibleFrame(_rect1, Color.Black, FrameStyle.Dashed);
                    }
                }
         
                void pictureBox1_MouseLeave(object sender, EventArgs e)
                {
                    EndPaintFrame();
                }
         
                void pictureBox1_MouseUp(object sender, MouseEventArgs e)
                {
                    EndPaintFrame();
                }
         
                void pictureBox1_MouseMove(object sender, MouseEventArgs e)
                {
                    if (_drawFrame)
                    {
                        //затираем уже нарисованную
                        ControlPaint.DrawReversibleFrame(_rect1, Color.Black, FrameStyle.Dashed);
                        //получаем новые экранные координаты
                        Point ScreenPoint =
                            PointToScreen(
                            new Point(e.X+pictureBox1.Left, e.Y+pictureBox1.Top));
                        _rect1 =
                            new Rectangle(
                            _rect1.X,
                            _rect1.Y,
                            ScreenPoint.X-_rect1.X,
                            ScreenPoint.Y-_rect1.Y);
                        //рисуем новую
                        ControlPaint.DrawReversibleFrame(_rect1, Color.Black, FrameStyle.Dashed);
                    }
                }
                void pictureBox1_MouseDown(object sender, MouseEventArgs e)
                {
                    //получаем экранные координаты
                    _rect1 = new Rectangle(
                        PointToScreen(new Point(e.X + pictureBox1.Left, e.Y + pictureBox1.Top)),
                        new Size(0, 0));
                    _drawFrame = true;
                }
      0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
      0 пользователей:


      Рейтинг@Mail.ru
      [ Script execution time: 0,0664 ]   [ 16 queries used ]   [ Generated: 25.04.24, 01:14 GMT ]