purebasic.info

PureBasic forum
Текущее время: Пт янв 19, 2018 4:09 pm

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 35 ]  На страницу 1, 2, 3  След.
Автор Сообщение
 Заголовок сообщения: Ввод дробных чисел в StringGadget
СообщениеДобавлено: Сб май 30, 2009 8:44 pm 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11079
Благодарил (а): 4 раз.
Поблагодарили: 384 раз.
Не секрет что в Пурике нет что-то типа #PB_String_Numeric, но поддержкой дробных чисел, т. е. возможность ввести разделительную точку. Это значит что при использовании флага #PB_String_Numeric мы не сможем ввести точку, отделяющую целую часть числа от дробной. :(
И при необходимости вводить дробные числа, нельзя использовать флаг #PB_String_Numeric.
Но если отказатся от него, то можно будет ввести любой символ, что не есть хорошо! :( :(
Значит надо "вручную" фильтровать вводимые символы.

Самый простой путь — отлавливать событие #PB_EventType_Change и считывать весь текст, анализировать его на наличие недопустивых символов и при наличии их уничтожить и вернуть в гаджет модифицированую строку текста.
Но это не очень хорошая идея. Во первых, надо будет запоминать текущую позицию курсора и восстанавливать его при замене текста, да и ввод символов будет заметен юзеру и сразу выдаст небольшой опыт программиста. Это хоть простой вариант, но его сразу можно отбросить!

В КодАрхиве есть пример StringGadget_FilterInput.pb, в котором при активации StringGadget'а ставится хук на прогу с помощью API функции SetWindowsHookEx, а при потере фокуса этого гаджета, хук снимается. Но это тже не лучший вариант, это тоже самое что если ради тарелки холодца резать целую свинью! :D

Есть ещё один вариант - перехватывать системную очередь сообщений винды для требуемого StringGadget'а. При этом StringGadget даже не узнает что были нажаты кнопки на клаве.
Значит наша задача вклинится между системной очередью сообщений и системной функцией-обработчиком событий для данного StringGadget'а, путём добавления своей Callback процедуры. Это нам позволит фильтровать сообщения для гаджета.
Теперь осталось выяснить как вклиниваться будем.
Использовать функцию SetWindowCallback в данном случае нельзя, т. к. с её помощью можно лишь "навесить" обработчик событий на окно, а StringGadget является дочерним окном нашего окна и поэтому мы не получим его события.
К счастью есть API функции GetWindowLong и SetWindowLong, с помощью которых можно "навесть" свою Callback процедуру перед системной. :)
Последовательность такая, сначала создаём саму Callback процедуру, затем с помощью GetWindowLong определяем адрес системной функции, обрабатывающей события StringGadget'а. Этот адрес нам понадобится для вызова этой функции в нашей Callback процедуры, с помощью API функции CallWindowProc. Ведь наша задача только фильтровать поток, а значит после фильтрации надо будет вызывать системный обрабаотчик событий гаджета.
После этого с помощью SetWindowLong надо зарегестрировать нашу Callback процедуру как обработчик событий требуемого гаджета.
Всё, процедура фильтрации есть! :)
Теперь можно фильтровать.
Нам надо отлавливать сообщение 258. Какая это константа, хз, число определено опытным путём.
Когда получено это сообщение, в wParam будет храниться код символа. Нам надо проанализировать его. если он соответствует допустимому, т. е. числу или точке, то ничего не делаем, а если НЕ соответсвует, то просто обнуляем сообщение — записываем 0 в переменную msg чтобы системная процедура не смогла его получить. :)
После этого, вызываем системную функцию с помощью CallWindowProc.

--------------
Вот пример.
В StringGadget можно воодить числа и только одну разделительную точку, да и то, если она не в начале строки.

Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Structure EditProc
 Gadget.l
 GadgetID.l
 *EditWndProc
EndStructure
 
 
Global EditProc_1.EditProc
 
Procedure EditWndProc(hwnd, msg, wParam, lParam)
Shared EditProc_1, EditProc_2
Protected *PointOldEditFunc
 
  If EditProc_1\GadgetID=hwnd
    Gadget=EditProc_1\Gadget
    *PointOldEditFunc=EditProc_1\EditWndProc
  Else
   ProcedureReturn 0
  EndIf
 
 
  If  msg=258
     If wParam=8 Or (wParam>='0' And wParam<='9')
     
     ElseIf wParam='.'
       Text.s=GetGadgetText(Gadget)
       If Text<>""
          If FindString(Text, ".",1)>0
             msg=0
             MessageBeep_(#MB_ICONERROR)
          EndIf
       Else
          msg=0
           MessageBeep_(#MB_ICONERROR)
       EndIf
     Else
      msg=0
       MessageBeep_(#MB_ICONERROR)
     EndIf
  EndIf
 
ProcedureReturn CallWindowProc_(*PointOldEditFunc,hwnd, msg, wParam, lParam)
EndProcedure
 
OpenWindow(1,0,0,100,40,"",#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CreateGadgetList(WindowID(1))
StringGadget(1,10,10,90,20,"")
 
      EditProc_1\Gadget=1
      EditProc_1\GadgetID=GadgetID(1)
      EditProc_1\EditWndProc=GetWindowLong_(EditProc_1\GadgetID, #GWL_WNDPROC)
      SetWindowLong_(EditProc_1\GadgetID, #GWL_WNDPROC, @EditWndProc())
 
Repeat
 Event=WaitWindowEvent()
Until Event=#PB_Event_CloseWindow
End
 


_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Вс май 31, 2009 5:08 am 
Не в сети
МОДЕРАТОР

Зарегистрирован: Вт дек 05, 2006 8:46 am
Сообщений: 6224
Благодарил (а): 16 раз.
Поблагодарили: 173 раз.
Пункты репутации: 48
Хорошая работа!

_________________
read-only


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Вт июн 02, 2009 11:25 am 
Не в сети
профессор

Зарегистрирован: Ср янв 14, 2009 4:12 pm
Сообщений: 2002
Благодарил (а): 12 раз.
Поблагодарили: 101 раз.
Пункты репутации: 43
До кучи :)
Так же не секрет что в Пурике нет что-то типа #PB_String_NumericHEX
В этом примере в StringGadget можно воодить числа только в HEX формате (ABCDEF 0-9)
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 
Structure EditProc
 Gadget.l
 GadgetID.l
 *EditWndProc
EndStructure
Global EditProc_1.EditProc
Procedure EditWndProc(hwnd, msg, wParam, lParam)
Shared EditProc_1, EditProc_2
Protected *PointOldEditFunc
  If EditProc_1\GadgetID=hwnd
    Gadget=EditProc_1\Gadget
    *PointOldEditFunc=EditProc_1\EditWndProc
  Else
   ProcedureReturn 0
  EndIf
  If  msg=258
         wParam = Asc(UCase(Chr(wParam)))
         Select wParam
                 ;"A""B""C""D""E""F""0""1""2""3""4""5""6""7""8""9"
            Case 8,65,66,67,68,69,70,48,49,50,51,52,53,54,55,56,57  
            Default
            msg=0
         EndSelect  
  EndIf
ProcedureReturn CallWindowProc_(*PointOldEditFunc,hwnd, msg, wParam, lParam)
EndProcedure
OpenWindow(1,0,0,100,40,"",#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
;CreateGadgetList(WindowID(1))
StringGadget(1,10,10,90,20,"")
      EditProc_1\Gadget=1
      EditProc_1\GadgetID=GadgetID(1)
      EditProc_1\EditWndProc=GetWindowLong_(EditProc_1\GadgetID, #GWL_WNDPROC)
      SetWindowLong_(EditProc_1\GadgetID, #GWL_WNDPROC, @EditWndProc())
Repeat
 Event=WaitWindowEvent()
Until Event=#PB_Event_CloseWindow
End



Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Вт июн 02, 2009 1:46 pm 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11079
Благодарил (а): 4 раз.
Поблагодарили: 384 раз.
Я думаю что сравинивать лучше так
Код:
1
2
3
4
5
If  msg=258 
    If wParam<>8 And (wParam<'0' Or wParam>'9') And (wParam<'a' Or wParam>'f') And (wParam<'A' Or wParam>'F')
      msg=0
    EndIf
  EndIf

Это нагляднее, да и процессор не будет тратить время на преобразоване строк :)

_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Чт июн 04, 2009 1:12 pm 
Не в сети
профессор

Зарегистрирован: Ср янв 14, 2009 4:12 pm
Сообщений: 2002
Благодарил (а): 12 раз.
Поблагодарили: 101 раз.
Пункты репутации: 43
Пётр писал(а):
процессор не будет тратить время на преобразоване строк

Эт чтобы в StringGadget'e сразу выводить заглавные буковки. Лично мне больше нравится, когда HEX числа отображаются заглавными букыами

_________________
Всё должно быть просто, настолько просто, насколько возможно, но не проще. (c) Альберт Эйнштейн
Изображение


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Чт июн 04, 2009 1:28 pm 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11079
Благодарил (а): 4 раз.
Поблагодарили: 384 раз.
А, да, это я не учёл.

_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Чт июл 23, 2009 11:19 am 
Не в сети
профессор

Зарегистрирован: Вт янв 13, 2009 2:41 pm
Сообщений: 369
Благодарил (а): 3 раз.
Поблагодарили: 17 раз.
Пункты репутации: 8
Люди, подскажите, как быть, если у меня много StringGadgetов, в которых нужно вводить дробные числа. Как не пытался, отображается только первый гаджет :(


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Чт июл 23, 2009 11:49 am 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11079
Благодарил (а): 4 раз.
Поблагодарили: 384 раз.
Fox писал(а):
Люди, подскажите, как быть, если у меня много StringGadgetов, в которых нужно вводить дробные числа.


Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
Structure EditProc 
 Gadget.l   ; Идентификатор гаджета
 GadgetID.l ; Системный идентификатор гаджета (хендл)
 *EditWndProc ; Процедура-обработчик событий
EndStructure
 
 
Global EditProc_1.EditProc
 
Procedure EditWndProc(hwnd, msg, wParam, lParam)
Protected *PointOldEditFunc  
 
  *GadgetInfa.EditProc = GetWindowLong_(hWnd,#GWL_USERDATA)
  Gadget=*GadgetInfa\Gadget
  *PointOldEditFunc=*GadgetInfa\EditWndProc
 
  If  msg=258
     If wParam=8 Or (wParam>='0' And wParam<='9')
     ElseIf wParam='.'
     
     SendMessage_(hWnd,#EM_GETSEL,@Min,@Max)
      If Min=0
        MessageBeep_(#MB_ICONERROR)
        ProcedureReturn 0
      EndIf
     
       Text.s=GetGadgetText(Gadget)
       If Text<>""
          If FindString(Text, ".",1)>0
             msg=0
             MessageBeep_(#MB_ICONERROR)
          EndIf
       Else
          msg=0
           MessageBeep_(#MB_ICONERROR)
       EndIf
     Else
      msg=0
       MessageBeep_(#MB_ICONERROR)
     EndIf
  EndIf
 
ProcedureReturn CallWindowProc_(*PointOldEditFunc,hwnd, msg, wParam, lParam)
EndProcedure
 
; Создаём StringGadget
Procedure StringGadget_Ex(Gadget, x, y, Width, Height, Content$, Flags)
 x=StringGadget(Gadget, x, y, Width, Height, Content$, Flags)
 If x
     *EditProc.EditProc = AllocateMemory(SizeOf(EditProc))
     *EditProc\Gadget=Gadget
     *EditProc\GadgetID=GadgetID(Gadget)
     *EditProc\EditWndProc=GetWindowLong_(*EditProc\GadgetID, #GWL_WNDPROC)
     SetWindowLong_(*EditProc\GadgetID,#GWL_USERDATA, *EditProc)
     SetWindowLong_(*EditProc\GadgetID, #GWL_WNDPROC, @EditWndProc())
 EndIf
ProcedureReturn x
EndProcedure
 
; Удаляем StringGadget
Procedure Free_StringGadget_Ex(Gadget)
 If IsGadget(Gadget)
  If GadgetType(Gadget)=#PB_GadgetType_String
    *mem=GetWindowLong_(GadgetID(Gadget),#GWL_USERDATA)
    If *mem
      FreeMemory(*mem)
    EndIf
    ProcedureReturn FreeGadget(Gadget)
  EndIf
 EndIf
ProcedureReturn 0
EndProcedure
 
OpenWindow(1,0,0,410,320,"",#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CreateGadgetList(WindowID(1))
 
Gadget=1
For x=1 To 4
 g_x=x*100-90
 For y=1 To 8
   g_y=y*40-30
   StringGadget_ex(Gadget,g_x,g_y,90,20,"",0)
   Gadget+1
 Next y
Next x
 
Repeat
 Event=WaitWindowEvent()
Until Event=#PB_Event_CloseWindow
End
 



Для добавления нового StringGadget'а с поддержкой дробных чисел, используй процедуру StringGadget_Ex
Для удаления такого гаджета используй процедуру Free_StringGadget_Ex

_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Сб июл 25, 2009 9:54 am 
Не в сети
профессор

Зарегистрирован: Вт янв 13, 2009 2:41 pm
Сообщений: 369
Благодарил (а): 3 раз.
Поблагодарили: 17 раз.
Пункты репутации: 8
Спасибо, код отлично работает, но есть один вопрос, критично ли освобождение памяти в данном случае, ведь для каждого гаджета выделяется всего 12 байт. Использовать предложенную процедуру мне ни лень, просто интересно знать мнение продвинутых программёров. :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Сб июл 25, 2009 10:27 am 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11079
Благодарил (а): 4 раз.
Поблагодарили: 384 раз.
Освобождение памяти желательно.
А если её не освбождать, то это уже "утечка" памяти...
Если все программисты будут так думать, то потребуется оперативка на пару террабайт! :D
Так что память нужно освобождать в любом случае, даже если это всего 1 байт.

_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Сб июл 25, 2009 12:16 pm 
Не в сети
профессор

Зарегистрирован: Вт янв 13, 2009 2:41 pm
Сообщений: 369
Благодарил (а): 3 раз.
Поблагодарили: 17 раз.
Пункты репутации: 8
Немного переделал процедуру, вдруг кому ещё пригодится:
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Procedure EditWndProc(hwnd, msg, wParam, lParam) 
Protected *PointOldEditFunc  
 
  *GadgetInfa.EditProc = GetWindowLong_(hWnd,#GWL_USERDATA)
  Gadget=*GadgetInfa\Gadget
  *PointOldEditFunc=*GadgetInfa\EditWndProc
 
  If  msg=258
     If wParam>='0' And wParam<='9'
 
       Text.s=GetGadgetText(Gadget)
       If Text<>""
       SendMessage_(hWnd,#EM_GETSEL,@Min,@Max)
             If Len(StringField(Text, 2, ".")) >= 2 And Min >= FindString(Text, ".", 1)
               msg=0
               MessageBeep_(#MB_ICONERROR)
             EndIf
       EndIf
       
     ElseIf wParam='.'
     
     SendMessage_(hWnd,#EM_GETSEL,@Min,@Max)
      If Min=0
        MessageBeep_(#MB_ICONERROR)
        ProcedureReturn 0
      EndIf
     
       Text.s=GetGadgetText(Gadget)
       If Text<>""
          If FindString(Text, ".",1)>0
             msg=0
             MessageBeep_(#MB_ICONERROR)
          EndIf
       Else
          msg=0
           MessageBeep_(#MB_ICONERROR)
       EndIf
       
     ElseIf wParam=8
     
     Else
      msg=0
       MessageBeep_(#MB_ICONERROR)
     EndIf
  EndIf
 
ProcedureReturn CallWindowProc_(*PointOldEditFunc,hwnd, msg, wParam, lParam)
EndProcedure


Теперь после точки можно вводить только 2 символа.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Сб фев 20, 2010 1:57 pm 
Не в сети
профессор

Зарегистрирован: Ср янв 14, 2009 4:12 pm
Сообщений: 2002
Благодарил (а): 12 раз.
Поблагодарили: 101 раз.
Пункты репутации: 43
Пётр
Этот способ перехвата работает только с символьно-цифровыми клавишами.
А как быть с клавишами Delete, BackSpase и Enter. Как перехватить их нажатие и запретить выполнять какие-либо действия в определенном гаджете? Может кто знает. В гугле ничего вразумительного не нашел :(

_________________
Всё должно быть просто, настолько просто, насколько возможно, но не проще. (c) Альберт Эйнштейн
Изображение


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Сб фев 20, 2010 6:38 pm 
Не в сети
МОДЕРАТОР

Зарегистрирован: Вт дек 05, 2006 8:46 am
Сообщений: 6224
Благодарил (а): 16 раз.
Поблагодарили: 173 раз.
Пункты репутации: 48
pablov писал(а):
А как быть с клавишами Delete, BackSpase и Enter.


Точно так же как и с другими клавишами.
Там только msg другой.Вставь в код процедуры следующее

Код:
1
2
3
4
5
6
7
8
If msg = 256
    If wParam=46 Or wParam=13; это коды del и  Enter
    msg=0
             MessageBeep_(#MB_ICONERROR)
     Debug " Нажата клавиша Del или Enter"        
    EndIf
  EndIf
 



И к стати, BackSpase можно отключить, если в оригинальном коде убрать строку If wParam=8, ибо код 8 это оно и есть!


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Сб фев 20, 2010 8:17 pm 
Не в сети
профессор

Зарегистрирован: Ср янв 14, 2009 4:12 pm
Сообщений: 2002
Благодарил (а): 12 раз.
Поблагодарили: 101 раз.
Пункты репутации: 43
kvitaliy
Спасибо, а то уже все мозги разбил на части
Кстати, откуда вы берете нужные значенения сообщений, msg = 258; msg = 256?
Пётр писал(а):
Нам надо отлавливать сообщение 258. Какая это константа, хз, число определено опытным путём.

Поделились бы опытом :D
kvitaliy писал(а):
И к стати, BackSpase можно отключить, если в оригинальном коде убрать строку If wParam=8, ибо код 8 это оно и есть!

Это я пробовал, msg обнуляется, но забой символа всеже происходит. А если так,
Код:
1
2
3
4
If msg = 256 
    If wParam=46 Or wParam=13 Or wParam=8; это коды del, Enter  и BackSpace
      msg=0
EndIf


тогда все работает

_________________
Всё должно быть просто, настолько просто, насколько возможно, но не проще. (c) Альберт Эйнштейн
Изображение


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Сб фев 20, 2010 8:31 pm 
Не в сети
МОДЕРАТОР

Зарегистрирован: Вт дек 05, 2006 8:46 am
Сообщений: 6224
Благодарил (а): 16 раз.
Поблагодарили: 173 раз.
Пункты репутации: 48
pablov писал(а):
Поделились бы опытом Very Happy


Все просто:
Код:
1
2
3
 Debug msg
 
 



И нажимай на интересующие тебя клавиши. Будет отображаться как нажатие так и "отжатие". Нам нужно нажатие.
Все очень просто? :D

_________________
read-only


Вернуться наверх
 Профиль  
 
Показать сообщения за:  Сортировать по:  
Начать новую тему Ответить на тему  [ Сообщений: 35 ]  На страницу 1, 2, 3  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

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


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group (блог о phpBB)
Сборка создана CMSart Studio
Русская поддержка phpBB