KB317479 Как нарисовать резиновую ленту ...

Полезные статьи и переводы интересных статей
Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

KB317479 Как нарисовать резиновую ленту ...

Сообщение Viper » 30.05.2006 (Вт) 14:06

HOW TO: Draw a Rubber Band or Focus Rectangle in Visual Basic .NET

(Как нарисовать резиновую ленту или прямоугольник фокуса в Visual Basic .NET)

PSS ID Number: 317479
Последнее изменение статьи 2.11.2004

Информация в этой статье применима к:

Microsoft .NET Framework Class Libraries 1.0
Microsoft .NET Framework Class Libraries 1.1
Microsoft Visual Basic .NET (2002)
Microsoft Visual Basic .NET (2003)

Данная статья ранее опубликована как Q317479
Версию этой статьи для Microsft Visual Studio .NET C# смотрите под номером 314945.

ОБЩАЯ ИНФОРМАЦИЯ

Резиновая лента или прямоугольник фокуса - это прямоугольник, который следует за указателем мыши, пока вы держите нажатой левую кнопку мыши. Эта техника обычно используется для определения границ выделенной зоны при работе с указателем мыши. В интерфейсе графического устройства (GDI) этот прямоугольник обычно реализуется при помощи растровых операция (ROPs). Однако, методы System.Drawing основаны на GDI+ (преемник GDI), который не поддерживает ROPs.

Эта статья показывает другой подход для реализации прямоугольника фокуса в .NET Framework.
В GDI прямоугльник фокуса часто рисуется при помощи ROP кодов. В частности, часто используются ROP2 коды R2_XORPEN и R2_NOT. Когда вы используете один из этих ROP2 кодов, вы можете стирать предыдущую линию, рисуя еще раз в той же позиции. Эта методика известна также как эффект исключающего ИЛИ (XOR).


Пример кода

Поскольку ROPs не доступны в GDI+ и в System.Drawing, вы должны использовать другой способ рисования обратимых линий при помощи этих средств. Например, вы можете средства PInvoke для взаимодействия с GDI. Однако, решение использующее только управляемый код доступно при использовании статического метода ControlPaint::DrawReversibleFrame(). Следующий код, написанный в Visual Basic .NET и готовый для вставки в класс формы в приложение по умолчанию Visual Basic .NET, демонстрирует этот способ:
Код: Выделить всё
Public Class Form1
   Inherits System.Windows.Forms.Form
   
   Dim bHaveMouse As Boolean
   Dim ptOriginal As Point
   Dim ptLast As Point

+[Windows Form Designer generated code]

   ' Конвертируем и нормализуем точки и рисуем обратимую рамку.
   Private Sub MyDrawReversibleRectangle(ByVal p1 As Point,ByVal p2 As Point)
      Dim rc As Rectangle
      ' Конвертируем точки в экранные координаты.
      p1 = PointToScreen(p1)
      p2 = PointToScreen(p2)
      ' Нормализуем прямоугольник.
      If (p1.X < p2.X) Then
         rc.X = p1.X
         rc.Width = p2.X - p1.X
      Else
         rc.X = p2.X
         rc.Width = p1.x - p2.X
      End If
      If (p1.Y < p2.Y) Then
         rc.Y = p1.Y
         rc.Height = p2.Y - p1.Y
      Else
         rc.Y = p2.Y
         rc.Height = p1.Y - p2.Y
      End If
      ' Рисуем обратимую рамку.
      ControlPaint.DrawReversibleFrame(rc, Color.Red, FrameStyle.Dashed)
   End Sub

   ' Вызывается при нажатии на левую кнопку мыши.
   Public Sub MyMouseMove(ByVal sender As System.Object,ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
      ' Запоминаем, что мы обрабатываем движение мыши.
      bHaveMouse = True
      ' Запоминаем "стартовую точку" прямоугольника резиновой ленты.
      ptOriginal.X = e.X
      prOriginal.Y = e.Y
      ' Специальное значение, указывающее на отсутстствие
      ' прямоугольника, который нужно стереть.
      ptLast.X = -1
      ptLast.Y = -1
   End Sub

   ' Вызывается, когда левая кнопка мыши отпускается.
   Public Sub MyMouseUp(ByVal sender As System.Object, ByVal e As System.Windows.MouseEventArgs) Handles MyBase.MouseUp
      ' Устанавливаем внутренний флаг, чтобы знать, что мы более не обрабатываем движение мыши.
      bHaveMouse = False
      ' Если мы рисовали раньше, рисуем еще раз в этой же позиции
      ' для удаления линий.
      if (ptLast.X <> -1) Then
         Dim ptCurrent As Point
         ptCurrent.X = e.X
         ptCurrent.Y = e.Y
         MyDrawReversibleRectangle(ptOriginal, ptLast)
      End If
      ' Устанавливаем флаги, указывающие на отсутствие линий для обращения.
      ptLast.X = -1
      ptLast.Y = -1
      ptOriginal.X = -1
      ptOriginal.Y = -1
   End Sub

   ' Вызывается при перемещении мыши.
   Public Sub MyMouseMove(ByVal sender As System.Object, ByVal e As System.Windows.MouseEventArgs) Handles MyBase.MouseMove
      Dim ptCurrent As Point
      ptCurrent.X = e.X
      ptCurrent.Y = e.Y
      ' Если мы обрабатываем движение мыши, то рисуем наши линии.
      If (bHaveMouse) Then
         ' Если мы рисовали раньше, рисуем еще раз в этой же позиции
         ' для удаления линий.
         If (ptLast.X <> -1) Then
            MyDrawReversibleRectangle(ptOriginal, ptLast)
         End If
         ' Обновляем послюднюю точку
         ptLast = ptCurrent
         ' Рисуем новые линии.
         MyDrawReversibleFrame(ptOriginal, ptCurrent)
      End If
   End Sub

   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      bHaveMouse = False
   End Sub
End Class


Заметьте, что это решение доступно только для вывода на экран. Для рисования обратимых линий на графических объектах вы должны либо взаимодействовать с GDI, либо вызывать Bitmap::LockBits() и непосредственно манипулировать с битами изображения.


Примечания переводчика:

1. Подвигло меня на этот перевод участившиеся топики на тему "как сделать selection tool в VB.NET".
2. Несмотря на то, что указано, что это применимо к VB.NET 2002 и VB.NET 2003, все успешно применяется и в VB.NET 2005 поскольку ничего нового в NET Framework в этой части не появилось.
3. Помимо использования функции ControlPaint.DrawReversibleFrame() можно также использовать функции ControlPaint.DrawReversibleLine() для рисования обратимых отрезков и ControlPaint.FillReversibleRectangle(). А вот сделать что-либо подобное для других фигур (например для круга) невозможно


Примечания модератора:

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

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 30.05.2006 (Вт) 15:05

Хм... Мне интересны мотивы разработчиков, которые исключили растровые операции из функционала .NET...
Lasciate ogni speranza, voi ch'entrate.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 30.05.2006 (Вт) 15:41

А потому что там пикселей нет, нет и ROP-ов.
Изображение

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 30.05.2006 (Вт) 16:08

Ужас.
А если я хочу выводить что-нибудь с точностью до физического пиксела?
Lasciate ogni speranza, voi ch'entrate.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 30.05.2006 (Вт) 16:13

А низя. MS всё собирается оградить программистов от особенностей оборудования, таких как разрешение и цветность.
Изображение

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 30.05.2006 (Вт) 16:26

Мдя...
А как мне указать, округлять пикселы как дискретные значения или как метрические?

P.S. Как только соберусь изучать .NET, так обязательно какая-нибудь фигня про него вылезает, начисто отбивающая желание его изучать.
Lasciate ogni speranza, voi ch'entrate.

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 30.05.2006 (Вт) 16:34

Глянул через ILDisasm как реализованы вышеупомянутые методы DrawReversibleFrame и DrawReversibleLine. Как и предполагалось, там вовсю юзаются такие функции GDI как SetROP, SelectObject, CreatePen и так далее... Видать не судьба дать обычному проггеру возможность доступа к ROP нормальным путем... Самим то можно... :(
Весь мир матрица, а мы в нем потоки байтов!

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 30.05.2006 (Вт) 16:43

alibek писал(а):P.S. Как только соберусь изучать .NET, так обязательно какая-нибудь фигня про него вылезает, начисто отбивающая желание его изучать.


Аналогично :)
const char *out = "|*0>78-,+<|"; size_t cc = char_traits<char>::length(out);
for (size_t i=0;i<cc;i++){cout<<static_cast<char>((out[i]^89));}cout<<endl;

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 30.05.2006 (Вт) 17:07

ну его этот .Net , назад к VC++ :lol:

FaKk2
El rebelde gur&#250;
El rebelde gur&#250;
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

Сообщение FaKk2 » 30.05.2006 (Вт) 17:42

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

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 30.05.2006 (Вт) 18:17

FaKk2, знаешь, почему на обычном листе в клетку (с клеткой в 5мм) 2 сантиметра -- это четыре клетки, но пять линий?
Lasciate ogni speranza, voi ch'entrate.

FaKk2
El rebelde gur&#250;
El rebelde gur&#250;
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

Сообщение FaKk2 » 30.05.2006 (Вт) 19:10

alibek
Ты интересуешься почему пять линий образуют четыре клетки, или почему четыре клетки это 2 сантиметра, несмотря на пять линий?
Для получения ответа надо продемонстрировать качества, позволяющие стать компетентным — внимательность, вдумчивость, наблюдательность, желание активно участвовать в выработке решения.

Amed
Алфизик
Алфизик
 
Сообщения: 5346
Зарегистрирован: 09.03.2003 (Вс) 9:26

Сообщение Amed » 30.05.2006 (Вт) 19:19

Второе.

FaKk2
El rebelde gur&#250;
El rebelde gur&#250;
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

Сообщение FaKk2 » 30.05.2006 (Вт) 19:21

Amed
Наверно, потому что так нарисовали. Или я чего то не улавливаю?
Для получения ответа надо продемонстрировать качества, позволяющие стать компетентным — внимательность, вдумчивость, наблюдательность, желание активно участвовать в выработке решения.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 30.05.2006 (Вт) 19:43

Я наверное непонятно выразился.

Есть принципиальная разница между линейкой и монитором, на котором нарисована линейка. На мониторе имеются физические пикселы (дискретная единица), которые отображают метрическую величину.
Поэтому на сантиметровой линейке на отрезке между 0 и 2 сантиметра находится 21 миллиметровое деление, а не 20 (хотя этот отрезок имеет длину 20 мм).
Поэтому для меня в некоторых случаях очень важно иметь доступ к физическим пикселам.

Хм... Перечитал, все-равно непонятно выразился.
Ладно, попробую еще раз, когда подумаю над формулировкой.
Но доступ к физическим пикселам важен. По крайней мере до тех пор, пока не появились мониторы на 300 DPI, в которых отдельные пикселы будут не различимы глазом.
Lasciate ogni speranza, voi ch'entrate.

FaKk2
El rebelde gur&#250;
El rebelde gur&#250;
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

Сообщение FaKk2 » 30.05.2006 (Вт) 20:28

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

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 31.05.2006 (Ср) 1:54

alibek, зато GDI+ обещает позволять одним и тем же кодом рисовать на мониторе и на плоттере :-D
Плюс, всё нарисованное может быть сохранено в EMF+-метафайл, и потом воспроизведено в любом устройстве, на любом разрешении.
Наверное поэтому же они, черти, запретили FloodFill :twisted:
Изображение


Вернуться в VBStreets Knowledge Base

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2

    TopList