forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   FAQ и уроки (http://forum.boolean.name/forumdisplay.php?f=110)
-   -   Пример 1. Обработка мышки. Класс TMouse (http://forum.boolean.name/showthread.php?t=11844)

Жека 04.02.2010 15:55

Пример 1. Обработка мышки. Класс TMouse
 
Вложений: 3
Обновил пример. Что нового:
- обработка колёсика мышки
- возможность обрабатывать все доступные кнопки мышки - состояния хранятся в массиве
- методы для получения значений полей класса, чтобы "случайно" не присвоить значение
- получение скоростей перемещения
- сброс нажатий (flush)

Количество кнопок для обработки указывается при создании экземпляра мышки:
Код:

Global mouse:TMouse = TMouse.fnCreate(3)
Получение состояний - по номеру кнопки:
Код:

If(mouse.fnKeyUp(1) = True)
----------------------------------------------------------------

Что можно сделать, используя данный класс:

• Определение текущих координат мышки (X, Y, Z)
• Определение момента нажатия кнопок мыши (hit)
• Определение нажатого состояния кнопок мыши (down)
• Определение момента отпускания кнопок мышки (up)
• Определение координат последнего щелчка (для каждой кнопки)
• Ограничение области перемещения мышки в виде прямоугольника
• Установка фиксированной позиции мышки для текущего прохода цикла

Работа показана на примере программы, рисующей отрезки.

Суть – при нажатии левой кнопки мышки создаётся отрезок, первая часть которого принимает координаты щелчка, а вторая «привязывается» к текущим координатам мышки. Удерживая нажатой левую кнопку мышки, можно изменять положение конца отрезка. При отпускании кнопки рисование текущего отрезка завершается, и он добавляется в список.

На экране показывается дополнительная информация о состоянии мышки.

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

Примечание: нет обработки колёсика мышки (кому надо - добавят легко).

Скриншот:
Вложение 8976

Исходный код:

Код:

Strict

Framework brl.d3d7max2d
Import brl.pngloader



'параметры экрана
Global screenW = 600
Global screenH = 700
Global screenD = 0
Local screenHertz = 75
Local screenFlags = GRAPHICS_BACKBUFFER


'заголовок окна приложения
AppTitle = "Использование класса TMouse"

'создаем окно
SetGraphicsDriver(D3D7Max2DDriver())
Graphics (screenW, screenH, screenD, screenHertz, screenFlags)


'флаг для условия выхода из игрового цикла
Global onRunning = True

'кнопки
Global keyEsc, keySpace, keyClose


'прячем стандартный курсор и ставим в середину окна
HideMouse()
MoveMouse(screenW * 0.5, screenH * 0.5)

'создаем "мышку" для обработки нажатий и прочего
Global mouse:TMouse = TMouse.fnCreate(3)
Local img:TImage = LoadImage("pointer.png")
mouse.fnSetPointer(img)
mouse.fnSetBounds(250, 200, 255, 300, False)


Local cntHit1, cntHit2, cntUped1, cntUped2


Global painter:TPainter = New TPainter


'главный цикл
While (onRunning = True)
       
        'получаем новые нажатия кнопок
        fnCheckKeyInput()
       
        'если нажали на крестик "закрыть" или Esc - выход
        If(keyEsc = True Or keyClose = True)
                onRunning = False
                Exit
        EndIf

        'вкл/выкл ограничивающий прямоугольник
        If(keySpace = True) mouse.onUseBounds = Not(mouse.onUseBounds)
       
        'обновляем мышку
        mouse.fnUpdate()
        'рисуем ограничивающий прямоугольник
        mouse.fnDrawBounds()
       
        If(mouse.fnKeyHit(1) = True)
                cntHit1:+1
                'тут что-нибудь делаем по нажатию левой кнопки мыши
        EndIf
       
        If(mouse.fnKeyHit(2) = True) cntHit2:+1
        If(mouse.fnKeyUp(1) = True) cntUped1:+1
        If(mouse.fnKeyUp(2) = True) cntUped2:+1
       
        SetColor(255, 255, 255)
       
        DrawText("cntHit1 = " + cntHit1, 20, 20)
        DrawText("cntHit2 = " + cntHit2, 20, 40)
       
        DrawText("mouseDown(1) = " + mouse.fnKeyDown(1), 20, 80)
        DrawText("mouseDown(2) = " + mouse.fnKeyDown(2), 20, 100)
       
        DrawText("cntUped1 = " + cntUped1, 20, 140)
        DrawText("cntUped2 = " + cntUped2, 20, 160)
       
        DrawText("curX = " + mouse.x, 20, 200)
        DrawText("curY = " + mouse.y, 20, 220)
       
        DrawText("hitX(1) = " + mouse.fnGetHitX(1), 20, 260)
        DrawText("hitY(1) = " + mouse.fnGetHitY(1), 20, 280)
       
        DrawText("Space - on/off bound rect", 20, 320)
       
        painter.fnUpdate(mouse.x, mouse.y)
        painter.fnDraw()
       
        'рисуем мышку
        mouse.fnDraw()
       
        Flip(0)
        Cls()
                       
Wend


End



'проверка состояния нажатых кнопок
Function fnCheckKeyInput()
        keyEsc = (KeyHit(KEY_ESCAPE) > 0)
        keySpace = (KeyHit(KEY_SPACE) > 0)
        keyClose = AppTerminate()
       
End Function



'класс мышки
Type TMouse
        Field x, y, z
        Field mHitX[], mHitY[]
        Field mHit[]
        Field mDown[]
        Field mUp[]
        Field pointer:TImage
        Field visible = True
        Field blockX, blockY, blockZ
       
        Field btnCount
        Field speedX, speedY, speedZ
       
        Field bx, by, bw, bh 'ограничивающая область
        Field onUseBounds
       
        Global k
       
       
        '"конструктор с параметром"
        Function fnCreate:TMouse(btnCnt = 3)
                Local m:TMouse = New TMouse
                m.btnCount = btnCnt
                m.mHit = New Int[btnCnt]
                m.mDown = New Int[btnCnt]
                m.mUp = New Int[btnCnt]
                m.mHitX = New Int[btnCnt]
                m.mHitY = New Int[btnCnt]
                Return m
        End Function
       
       
        'обновление
        Method fnUpdate()
               
                If(blockX = False)
                        x = MouseX()
                        speedX = MouseXSpeed()
                EndIf
               
                If(blockY = False)
                        y = MouseY()
                        speedY = MouseYSpeed()
                EndIf
               
                If(blockZ = False)
                        z = MouseZ()
                        speedZ = MouseZSpeed()
                EndIf
               
                blockX = False
                blockY = False
                blockZ = False
               
                'корректировка позиции
                fnCorrectPosByBounds()
               
                For k = 0 Until btnCount
                        mUp[k] = mDown[k]
                        mHit[k] = (MouseHit(k + 1) > 0)
                        mDown[k] = MouseDown(k + 1)
                       
                        If(mHit[k] = True)
                                mHitX[k] = x
                                mHitY[k] = y
                        EndIf
                       
                        If(mUp[k] = True And mDown[k] = False)
                                mUp[k] = True
                        Else
                                mUp[k] = False
                        EndIf
                       
                Next
               
        End Method
       
       
        'корректировка позиции - возвращаем в допустимую область
        Method fnCorrectPosByBounds()
                If(onUseBounds = False) Return
               
                If(x < bx) x = bx
                If(y < by) y = by
                If(x > bx + bw) x = bx + bw
                If(y > by + bh) y = by + bh
                MoveMouse(x, y)
       
        End Method
               
       
        'блокировка на 1 ход в указанной позиции
        Method fnBlock(px, py, pz = -1)
                               
                If(px >= 0)
                        x = px
                        blockX = True
                EndIf
                If(py >= 0)
                        y = py
                        blockY = True
                EndIf
                If(pz >= 0)
                        z = pz
                        blockZ = True
                EndIf
               
                MoveMouse(x, y)
               
        End Method
       
       
        'установка картинки указателя мыши
        Method fnSetPointer(img:TImage)
                pointer = img
        End Method
       
       
        'рисование
        Method fnDraw(dx = 0, dy = 0)
                If(visible = False Or pointer = Null) Return
               
                SetAlpha(1)
                SetColor(255, 255, 255)
                DrawImage(pointer, x + dx, y + dy)
               
        End Method
       
       
        'рисование ограничивающего прямоугольника
        Method fnDrawBounds()
                If(onUseBounds = True)
                        SetColor(155, 155, 155)
                        DrawLine(bx, by, bx + bw, by)
                        DrawLine(bx + bw, by, bx + bw, by + bh)
                        DrawLine(bx + bw, by + bh, bx, by + bh)
                        DrawLine(bx, by + bh, bx, by)
                EndIf
        End Method
       
       
        'показать указатель
        Method fnShow()
                visible = True
        End Method
       
       
        'скрыть указатель
        Method fnHide()
                visible = False
        End Method
       
       
        'ограничивающая область
        Method fnSetBounds(px, py, pw, ph, use = True)
                bx = px
                by = py
                bw = pw
                bh = ph
                onUseBounds = use
        End Method
       
       
        'проверка - щелчок кнопки
        Method fnKeyHit(button)
                If(button < 1 Or button > btnCount) Return False
                Return mHit[button - 1]
        End Method
       
       
        'проверка - удержание нажатой кнопки
        Method fnKeyDown(button)
                If(button < 1 Or button > btnCount) Return False
                Return mDown[button - 1]
        End Method
       
       
        'проверка - отпускание кнопки
        Method fnKeyUp(button)
                If(button < 1 Or button > btnCount) Return False
                Return mUp[button - 1]
        End Method
       
       
        'Х-координата последнего нажатия кнопки
        Method fnGetHitX(button = 1)
                If(button < 1 Or button > btnCount) Return - 1
                Return mHitX[button - 1]
        End Method
       
       
        'У-координата последнего нажатия кнопки
        Method fnGetHitY(button = 1)
                If(button < 1 Or button > btnCount) Return - 1
                Return mHitY[button - 1]
        End Method
       
       
        'возвращение координаты Х
        Method fnGetX()
                Return x
        End Method
       
       
        'возвращение координаты Y
        Method fnGetY()
                Return y
        End Method
       
       
        'возвращение координаты Z
        Method fnGetZ()
                Return z
        End Method
       
       
        'возвращение скорости по Х
        Method fnGetSpeedX()
                Return speedX
        End Method
       
       
        'возвращение скорости по Y
        Method fnGetSpeedY()
                Return speedY
        End Method
       
       
        'возвращение скорости по Z
        Method fnGetSpeedZ()
                Return speedZ
        End Method
       
       
        'сброс состояний всех кнопок
        Method fnFlush()
                FlushMouse()
                For k = 0 Until btnCount
                        mHit[k] = False
                        mDown[k] = False
                        mUp[k] = False
                Next
        End Method
       
End Type



'рисовалка линий
Type TPainter
        Field x0:Float, y0:Float
        Field lineWidth = 2
        Field curLine:TLine
       
        Global list:TList = New TList 'список для отрезков
        Global line:TLine
        Global linesCount
       
       
        'обновление
        Method fnUpdate(x:Float, y:Float)
               
                'при щелчке мыши создаём новую линию
                If(mouse.fnKeyHit(1) = True)
                        curLine = TLine.fnCreate(x, y, x, y)
                EndIf
               
                'двигаем конец за мышкой
                If(curLine <> Null) curLine.fnSetEnd(x, y)
               
                'при отпускании кнопки мыши добавляем линию в список
                If(mouse.fnKeyUp(1) = True)
                        list.AddLast(curLine)
                        linesCount:+1
                        curLine = Null
                EndIf
               
        End Method
       
       
        'рисование
        Method fnDraw()
                SetColor(255, 255, 255)
                SetLineWidth (lineWidth)
                For line = EachIn list
                        line.fnDraw(x0, y0)
                Next
                line = Null
               
                If(curLine <> Null) curLine.fnDraw(x0, y0)
        End Method
       
       
        'сдвинуть начало координат
        Method fnMove(dx:Float, dy:Float)
                x0:+dx
                y0:+dy
        End Method
       
End Type



'линия
Type TLine
        Field x1:Float, x2:Float, y1:Float, y2:Float
       
        'конструктор с параметрами
        Function fnCreate:TLine(x1:Float, y1:Float, x2:Float, y2:Float)
                Local ln:TLine = New TLine
                ln.x1 = x1
                ln.y1 = y1
                ln.x2 = x2
                ln.y2 = y2
                Return ln
        End Function
       
       
        'установка начальных координат
        Method fnSetStart(x:Float, y:Float)
                x1 = x
                y1 = y
        End Method
       
       
        'установка конечных координат
        Method fnSetEnd(x:Float, y:Float)
                x2 = x
                y2 = y
        End Method
       
       
        'рисование
        Method fnDraw(x0:Float, y0:Float)
                DrawLine(x0 + x1, y0 + y1, x0 + x2, y0 + y2)
        End Method
       
End Type


G.A.D 04.02.2010 19:13

Ответ: Пример 1. Обработка мышки. Класс TMouse
 
Молодец!
но зачем?

Randomize 05.02.2010 03:06

Ответ: Пример 1. Обработка мышки. Класс TMouse
 
При выходе мышки за пределы получается "дрыганье".
Отнимай от позиции x и y MouseXSpeed() и MouseYSpeed().
Стандартно на мыши 3 кнопки, но бывает и больше так что по хорошему использовать массив.
Курсор - картинка внутри класса тоже не очень корректно.
Придётся переписывать класс если курсор динамический (анимационный и меняется от определённых событий)

Жека 05.02.2010 08:11

Ответ: Пример 1. Обработка мышки. Класс TMouse
 
Цитата:

Сообщение от G.A.D
Молодец!
но зачем?

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

Цитата:

Сообщение от Randomize
При выходе мышки за пределы получается "дрыганье".
Отнимай от позиции x и y MouseXSpeed() и MouseYSpeed().

Рисуемая картинка курсора не имеет склонности дёргаться, а системный курсор - да, т.к. он рисуется самой системой. Для него самое то отнимать скорость:)

Цитата:

Сообщение от Randomize
Стандартно на мыши 3 кнопки, но бывает и больше так что по хорошему использовать массив.

Я тоже так думал. Сделал.

Цитата:

Сообщение от Randomize
Курсор - картинка внутри класса тоже не очень корректно.
Придётся переписывать класс если курсор динамический (анимационный и меняется от определённых событий)

Для таких случаев просто координаты понадобятся. Ну или обработку состояний в классе мышки дописать, тогда всё мышиное в одном месте будет.
Переносимость в другой проект - легко, т.к. изменения незначительными окажутся.

Картинка внутри класса не оч корректна из-за нестыковки с менеджером ресурсов или что-то ещё?

Randomize 05.02.2010 11:03

Ответ: Пример 1. Обработка мышки. Класс TMouse
 
Создай обьект TCursor
От которого сделай два класса наследника.
TAnimateCursor
TStaticCursor
Хотя по хорошему мышь и курсор должны быть на разных уровнях абстрауции.

Жека 05.02.2010 13:44

Ответ: Пример 1. Обработка мышки. Класс TMouse
 
Они мне не нужны.:)

Randomize 09.02.2010 16:24

Ответ: Пример 1. Обработка мышки. Класс TMouse
 
За MouseUP спасибо :D
Сейчас понадобилось и чтоб голову не ломать взял кусочек твоего кода.

Кстати заметил тут:
Global k
переменная "k" спользуется для цикла.
For k = 0 Until btnCount
Не легче бы избавится от этого глобала так:
For Local k% = 0 Until btnCount
Или тебя беспокоит, что локальная переменная будет каждый раз создаватся?

moka 09.02.2010 20:20

Ответ: Пример 1. Обработка мышки. Класс TMouse
 
Делать проверку на зажатие каждый цикл - затратно.
Зажатие проверяй Только после нажатия, и до отжатия.
Если будешь релизовывать класс для клавиатуры, используй GetChar.Функции получения инпута, не такие и шустрые.

Randomize 10.02.2010 08:35

Ответ: Пример 1. Обработка мышки. Класс TMouse
 
0-1 ms на выполнение Mouse.Update()

Жека 10.02.2010 13:44

Ответ: Пример 1. Обработка мышки. Класс TMouse
 
Цитата:

Сообщение от Randomize (Сообщение 136689)
За MouseUP спасибо :D
Сейчас понадобилось и чтоб голову не ломать взял кусочек твоего кода.

Вот и хорошо:)

Цитата:

Сообщение от Randomize (Сообщение 136689)
Или тебя беспокоит, что локальная переменная будет каждый раз создаватся?

Что-то вроде того. Для одного места использования особого смысла нет, а для нескольких я стараюсь делать глобальные.


Часовой пояс GMT +4, время: 13:27.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot