![](images/chestnut/misc/left.gif) |
04.02.2010, 15:55
|
#1
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Пример 1. Обработка мышки. Класс TMouse
Обновил пример. Что нового:
- обработка колёсика мышки
- возможность обрабатывать все доступные кнопки мышки - состояния хранятся в массиве
- методы для получения значений полей класса, чтобы "случайно" не присвоить значение
- получение скоростей перемещения
- сброс нажатий (flush)
Количество кнопок для обработки указывается при создании экземпляра мышки:
Global mouse:TMouse = TMouse.fnCreate(3)
Получение состояний - по номеру кнопки:
If(mouse.fnKeyUp(1) = True)
----------------------------------------------------------------
Что можно сделать, используя данный класс:
• Определение текущих координат мышки (X, Y, Z)
• Определение момента нажатия кнопок мыши (hit)
• Определение нажатого состояния кнопок мыши (down)
• Определение момента отпускания кнопок мышки (up)
• Определение координат последнего щелчка ( для каждой кнопки)
• Ограничение области перемещения мышки в виде прямоугольника
• Установка фиксированной позиции мышки для текущего прохода цикла
Работа показана на примере программы, рисующей отрезки.
Суть – при нажатии левой кнопки мышки создаётся отрезок, первая часть которого принимает координаты щелчка, а вторая «привязывается» к текущим координатам мышки. Удерживая нажатой левую кнопку мышки, можно изменять положение конца отрезка. При отпускании кнопки рисование текущего отрезка завершается, и он добавляется в список.
На экране показывается дополнительная информация о состоянии мышки.
По нажатию на пробел включается/отключается ограничение на передвижение мышки. При включённом рисуется ограничивающий прямоугольник.
Примечание: нет обработки колёсика мышки (кому надо - добавят легко).
Скриншот:
Исходный код:
![](images/chestnut/misc/code_html.gif)
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
Последний раз редактировалось Жека, 05.02.2010 в 07:48.
Причина: Дополненил пример.
|
(Offline)
|
|
Эти 3 пользователя(ей) сказали Спасибо Жека за это полезное сообщение:
|
|
04.02.2010, 19:13
|
#2
|
Разработчик
Регистрация: 28.02.2009
Сообщений: 434
Написано 44 полезных сообщений (для 96 пользователей)
|
Ответ: Пример 1. Обработка мышки. Класс TMouse
Молодец!
но зачем?
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
05.02.2010, 03:06
|
#3
|
[object Object]
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,356
Написано 2,472 полезных сообщений (для 6,854 пользователей)
|
Ответ: Пример 1. Обработка мышки. Класс TMouse
При выходе мышки за пределы получается "дрыганье".
Отнимай от позиции x и y MouseXSpeed() и MouseYSpeed().
Стандартно на мыши 3 кнопки, но бывает и больше так что по хорошему использовать массив.
Курсор - картинка внутри класса тоже не очень корректно.
Придётся переписывать класс если курсор динамический (анимационный и меняется от определённых событий)
__________________
Retry, Abort, Ignore? █
Intel Core i7-9700 4.70 Ghz; 64Gb; Nvidia RTX 3070
AMD Ryzen 7 3800X 4.3Ghz; 64Gb; Nvidia 1070Ti
AMD Ryzen 7 1700X 3.4Ghz; 8Gb; AMD RX 570
AMD Athlon II 2.6Ghz; 8Gb; Nvidia GTX 750 Ti
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
05.02.2010, 08:11
|
#4
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Ответ: Пример 1. Обработка мышки. Класс TMouse
Сообщение от G.A.D
Молодец!
но зачем?
|
Мне удобнее, когда все переменные для мышки в одном классе. Создал экземпляр и обращайся к ним через точечку.
И новичкам может пригодиться.
Сообщение от Randomize
При выходе мышки за пределы получается "дрыганье".
Отнимай от позиции x и y MouseXSpeed() и MouseYSpeed().
|
Рисуемая картинка курсора не имеет склонности дёргаться, а системный курсор - да, т.к. он рисуется самой системой. Для него самое то отнимать скорость
Сообщение от Randomize
Стандартно на мыши 3 кнопки, но бывает и больше так что по хорошему использовать массив.
|
Я тоже так думал. Сделал.
Сообщение от Randomize
Курсор - картинка внутри класса тоже не очень корректно.
Придётся переписывать класс если курсор динамический (анимационный и меняется от определённых событий)
|
Для таких случаев просто координаты понадобятся. Ну или обработку состояний в классе мышки дописать, тогда всё мышиное в одном месте будет.
Переносимость в другой проект - легко, т.к. изменения незначительными окажутся.
Картинка внутри класса не оч корректна из-за нестыковки с менеджером ресурсов или что-то ещё?
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
05.02.2010, 11:03
|
#5
|
[object Object]
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,356
Написано 2,472 полезных сообщений (для 6,854 пользователей)
|
Ответ: Пример 1. Обработка мышки. Класс TMouse
Создай обьект TCursor
От которого сделай два класса наследника.
TAnimateCursor
TStaticCursor
Хотя по хорошему мышь и курсор должны быть на разных уровнях абстрауции.
__________________
Retry, Abort, Ignore? █
Intel Core i7-9700 4.70 Ghz; 64Gb; Nvidia RTX 3070
AMD Ryzen 7 3800X 4.3Ghz; 64Gb; Nvidia 1070Ti
AMD Ryzen 7 1700X 3.4Ghz; 8Gb; AMD RX 570
AMD Athlon II 2.6Ghz; 8Gb; Nvidia GTX 750 Ti
|
(Offline)
|
|
05.02.2010, 13:44
|
#6
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Ответ: Пример 1. Обработка мышки. Класс TMouse
Они мне не нужны. ![:)](images/smilies/smile.gif)
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
09.02.2010, 16:24
|
#7
|
[object Object]
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,356
Написано 2,472 полезных сообщений (для 6,854 пользователей)
|
Ответ: Пример 1. Обработка мышки. Класс TMouse
За MouseUP спасибо :D
Сейчас понадобилось и чтоб голову не ломать взял кусочек твоего кода.
Кстати заметил тут:
Global k
переменная "k" спользуется для цикла.
For k = 0 Until btnCount
Не легче бы избавится от этого глобала так:
For Local k% = 0 Until btnCount
Или тебя беспокоит, что локальная переменная будет каждый раз создаватся?
__________________
Retry, Abort, Ignore? █
Intel Core i7-9700 4.70 Ghz; 64Gb; Nvidia RTX 3070
AMD Ryzen 7 3800X 4.3Ghz; 64Gb; Nvidia 1070Ti
AMD Ryzen 7 1700X 3.4Ghz; 8Gb; AMD RX 570
AMD Athlon II 2.6Ghz; 8Gb; Nvidia GTX 750 Ti
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
09.02.2010, 20:20
|
#8
|
.
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений (для 6,863 пользователей)
|
Ответ: Пример 1. Обработка мышки. Класс TMouse
Делать проверку на зажатие каждый цикл - затратно.
Зажатие проверяй Только после нажатия, и до отжатия.
Если будешь релизовывать класс для клавиатуры, используй GetChar.Функции получения инпута, не такие и шустрые.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
10.02.2010, 08:35
|
#9
|
[object Object]
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,356
Написано 2,472 полезных сообщений (для 6,854 пользователей)
|
Ответ: Пример 1. Обработка мышки. Класс TMouse
0-1 ms на выполнение Mouse.Update()
__________________
Retry, Abort, Ignore? █
Intel Core i7-9700 4.70 Ghz; 64Gb; Nvidia RTX 3070
AMD Ryzen 7 3800X 4.3Ghz; 64Gb; Nvidia 1070Ti
AMD Ryzen 7 1700X 3.4Ghz; 8Gb; AMD RX 570
AMD Athlon II 2.6Ghz; 8Gb; Nvidia GTX 750 Ti
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
10.02.2010, 13:44
|
#10
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Ответ: Пример 1. Обработка мышки. Класс TMouse
Сообщение от Randomize
За MouseUP спасибо :D
Сейчас понадобилось и чтоб голову не ломать взял кусочек твоего кода.
|
Вот и хорошо
Сообщение от Randomize
Или тебя беспокоит, что локальная переменная будет каждый раз создаватся?
|
Что-то вроде того. Для одного места использования особого смысла нет, а для нескольких я стараюсь делать глобальные.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 02:24.
|