Rapid-Q Documentation by William Yu (c)1999 Глава 12

 

12. Графика под Windows (Graphics under Windows)

Информация, содержащаяся в этой главе в основном не применима под Линукс, за исключением нескольких первых разделов.
По сравнению с DOS существуют отличия в показе графики под Windows, в основном из-за многозадачной природы Windows и управления ее событиями.

12.1  Графика под DOS против графики под Windows (Graphics under DOS versus Windows )

Если вы хорошо знакомы с программированием под ДОС и не очень -  с программированием под Windowsds возможно отметите несколько значительных отличий программирования под этими двумя ОС. Под ДОС это более просто, так как вы не должны заботится о том,что другие программы будут прерывать ваше приложение. Это означает что вы показывете/рисуете на экране не будет исчезать само по себе, вы должны только беспокоиться о том. что нарисовать следующим.
 This means what you display/draw on the screen won't erase itself magically, you only worry about what to draw next.
Однако есть одно тонкое отличие под Windows. Хотя совершенно безопасно рисовать на форме имеетс несколько следствий. Наиболее очевидно, что другая программа может прерывать выполнение\отображение вашей программы. Вспоните также о мимнимзации окна или перекрытии его другим окном. Как Windows узнает, что надо перересовывать когда ваше окно снова получает фокус?
Вы можете подумать, что Windows yнастолько азумна, чтобы самостоятельно перересовывать ранее скрытую часть, но к сожалению все не так просто. Ваша программа должна сообщить Windows, что требуется перерисовать.Windows будет говорить вам, что ваша форма требует перерисовки, посылая сообщения вашей форме. Обычно OnPaint (WM_PAINT) сообщение посылается окну, которое требует перерисовки.
На вас лежит ответственностьобеспечить OnPaint процедуру для формы которая требует перерисовки.

12.2 Какие компоненты требуют перерисовки (What components require painting)?
Все визуальные компоненты, но к счастью большую часть работы берет на себя Windows.
 например нет необходимости обеспечивать обработку OnPaint события для Qbutton класса, так как он уже встроен в этот класс. Конечно вы можете написать свой собственный класс Qbutton (см. главу 10)чтобы дать пользователю возможность написать собственный обработчик OnPaint.
Qform и QCanvas это два обычно используемых компонента для рисования графики. Вы можете представить QCanvas как ваш основной DOS графический экран. То что необходимо нарисовать должно быть описано внутри процедуры OnPaint.
    DECLARE SUB CanvasPaint (Sender AS QCanvas)

    CREATE Form AS QForm
        CREATE Canvas AS QCanvas
            OnPaint = CanvasPaint
        END CREATE
        ShowModal
    END CREATE

    SUB CanvasPaint (Sender AS QCanvas)
        Sender.FillRect(10,10,100,100,&HFF0000)      '-- Blue box Синий прямоугольник
    END   SUB         


   Когда окно  скроется под другим окном    и снова    появится, то синий прямоугольник перерисуется.Теперь попробуйте написать что-то не использующее процедуру OnPaint.
    CREATE Form AS QForm
        CREATE Canvas AS QCanvas
            FillRect(10,10,100,100,&HFF0000)      '-- Blue box
        END CREATE
        Form.ShowModal
    END CREATE



Заметили что-нибудь? Да, синий прямоугольник не появился.  Сообщение для о необходимости рисования было послано когда форма впервые появилать на экране и поскольку вы не написали какой-либо процедуры OnPaint, то ничего и не нарисовалось. Что же на самом деле произошло с этим FillRect кодом? На самом деле ничего,он выполнился, но следующее сообщение о перерисовке стерло нарисованное.

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

    DECLARE SUB ButtonClick

    CREATE Form AS QForm
        CREATE Button AS QButton
          OnClick = ButtonClick
        END CREATE
        CREATE Canvas AS QCanvas
        END CREATE
        ShowModal
    END CREATE

    SUB ButtonClick
        Canvas.FillRect(10,10,100,100,&HFF0000)
    END SUB
             
        Когда вы нажимаете на кнопку синий прямоугольник 
рисуется, однако когда вы перерисовываете окно, прямоугольник исчезает.

12.3 Динамическое рисование графических объектов (Drawing graphics dynamically )

Возникает вопрос, если рисование всех объектов производится через процедуру OnPaint, то каким образом можно динамически перерисовывать графические объекты без из стирания?
Для этих целей необходимо использовать невидимый объект bitmap и потом в процедуре OnPaint просто использовать Draw метод для отрисовки графики. Вы можете использовать компонент QbitMap как невидимую графическую страницу. Ниже приведен пример кода.

DECLARE SUB CanvasPaint (Sender AS QCanvas)
DECLARE SUB ButtonClick (Sender AS QButton)

' Create bitmap for off-screen use
DIM BitMap AS QBITMAP
    BitMap.Height = 100
    BitMap.Width = 100
    BitMap.Paint(0,0,0,0)

CREATE Form AS QForm
    Center
    Caption = "Simple graphics demonstration"
    CREATE Canvas AS QCanvas
        OnPaint = CanvasPaint
    END CREATE
    CREATE SquareButton AS QButton
        Caption = "Draw Square"
        OnClick = ButtonClick
        Left = 150
    END CREATE
    CREATE CircleButton AS QButton
        Caption = "Draw Circle"
        OnClick = ButtonClick
        Left = 150
        Top = 50
    END CREATE
    CREATE LineButton AS QButton
        Caption = "Draw Line"
        OnClick = ButtonClick
        Left = 150
        Top = 100
    END CREATE
    ShowModal
END CREATE


SUB CanvasPaint (Sender AS QCanvas)
    Sender.Draw(0,0,Bitmap.BMP)
END SUB

SUB ButtonClick (Sender AS QButton)
    SELECT CASE Sender.Caption
        CASE "Draw Square"
            Bitmap.FillRect(10,10,50,50,&HFF0000)
        CASE "Draw Circle"
            Bitmap.Circle(10,60,50,110,&H0000FF,&H0000FF)
        CASE "Draw Line"
            Bitmap.Line(50,50,90,90,&H00FF00)
    END SELECT
    Canvas.Repaint       '-- Tell Canvas to repaint itself.
END SUB
Результат:
Output

Детали:
Первым делом создается и инициализируется компонент BitMap. Поскольку Qbitmap это невидимый компонент он не принимает никаких сообщений о перерисовке и поэтому все нарисованное на нем сохраняется. Когда BitMap будет подготовлен наша процедура OnPaint  для QCanvas может использовать метод Draw для отрисовки BitMap на Canvas. Это то, что называется двойной буферизацией, подобная техника используется в DirectX.

12.4  Рисование графики в списках и таблицах (Ownerdraw List and Combo Boxes (including QStringGrid)
Перерисовывающиеся списки и комбобоксы позволяют вам заменять стандартные процедуры рисования этих объектов.  На самом деле изменить внешний вид этих компонентов не удастся так что это возможно не то, что вам хотелось бы.
Возможно только изменить метод отрисовки данных в этих списках. Вы можете вставить картинку или изменить шрифт или цвет для каждого элемента списка в отдельности.
Имеется два основных вида перерисовываемых списков
  • 1. OwnerDrawFixed
  • 2. OwnerDrawVariable

 Фиксированный  тип используется когда элементы списка имеют одинаковую высоту

Но могут быть случаи, когда объекты, например рисунки имеют разную высоту.  В этом случае лучше использовать список с переменной высотой элементов. Едиственная проблема в этом случае заключается в необходимости задавать высоту каждого элемента программынм способом. Эта задача возлагается на программиста
В большинстве случаев это не представляет большой проблемы, но необходимо где-то хранить эту дополнительную информацию о высоте каждого элемента. Как это сделать в каждом случае выбираете вы сами. Вы можете найти работающий пример перерисовываемых лист\комбобоксов в файле LISTBOX.BAS из архива EXAMPLES.ZIP Вы можете переписать этот код для работы с комбобоксом. Заметьте, что вместо процедуры OnPaint используется процедура OnDrawItem.

Code Детали:

  SUB ListBoxDrawItem(Index AS INTEGER, State AS BYTE, Rect AS QRECT)
    IF State = 0 THEN
      '-- Selected
      ListBox.FillRect(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom, &H00FF00)
    ELSE
      ListBox.FillRect(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom, &HFFFFFF)
    END IF
    ListBox.TextOut(100, Rect.Top+(Rect.Bottom-Rect.Top)/4, ListBox.Item(index), 0, -1)
    ListBox.Draw(Rect.Left, Rect.Top, Bitmap(Index).BMP)
  END SUB
Надеюсь код достаточно понятен, но несколько моментов следует отметить. Первое, это то, что не требуется полностью перерисовывать весь листбокс, правильнее посылать сообщение о перерисовке каждый раз, когда элемент списка изменился. Элемент занимает определенный прямоугольник в списке и сообщение OnDrawItem посылает информацию о нем через параметр Rect. Вы не должны игнорировать этот шаг, эта возможность специально дана вам! (Другими словами не пытайтесь рисовать вне региона, это не ваша задача! Я не описываю работу с QstringGrid в этом разделе,но идея та же самая. Вы можете обрабатывать событие OnDrawCell так же как OnDrawItem для списка.

12.5 Использование DirectX (Using DirectX)
В чем причина популярности DirectX? На этот вопрос коротко можно ответить не вдаваясь в детали. DirectX значительно быстрее чем Windows GDI (и OpenGL в большинстве случаев). DirectX поддерживается большинством видеокарт, бесплатно для использования и обеспечивает большое количество необходимых графических команд, которые не приходится писать самому. Оно широко распространео и легко для использования.
DirectX v8 устанавливается на всех компьютерах, работающих под управлением WindowsXP. Для работы Rapid-Q требуется версия 5 и выше. Rapid-Q поддерживает не все возможности DirectX, не поддерживаются джойстик.
Для использования DirectX под Rapid-Q вы должны знать две вещи:
  • 1. Все рисование выводится сначала на скрытую экранную страницу
  • 2. Небходимо использовать команду FLIP для показа на экране содержимого этой страницы.
В сущности вы можете рассматривать эту невидимую страницу как постоянный инструмент для вас (подобно испльзованию QbitMap в предыдущем примере). Операция FLIP подобна операции repaint. Когда станут ясны эти две вещи, остальное станет тоже понятным. Вы рисуете на DirectX Screen подбно как на QCanvas или QBitmap и затем используете FLIP для вывода этой страницы на экран когда картинка будет готова. Есть однако одна важная тема, такая как QDXTimer.
QDXTimer это специальный таймер, применяемы ри работе с DirectX. Он обеспечивает повышенную точность отсчет времени чем Qtimer и управляет частотой обновления экрана, так чтобы программа не выполнялась слишком быстро. Рекомендуется использовать QDXTimer при анимции графики под Windows.


Prev Глава Содержание Next Глава
>