Numeric Entry in an EditBox

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

RNBW wrote:The thing I don't like about it, is that when an inadmissable character is entered the cursor returns to the beginning of the entry. I would rather it stayed where it was, or moved to the end, but I don't know how to achieve this.
By subclassing the edit control.
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

jj2007 wrote:
RNBW wrote:The thing I don't like about it, is that when an inadmissable character is entered the cursor returns to the beginning of the entry. I would rather it stayed where it was, or moved to the end, but I don't know how to achieve this.
By subclassing the edit control.
Looking back at your earlier post on subclassing.
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

jj2007 wrote:
RNBW wrote:The thing I don't like about it, is that when an inadmissable character is entered the cursor returns to the beginning of the entry. I would rather it stayed where it was, or moved to the end, but I don't know how to achieve this.
By subclassing the edit control.
I've played around with the code you gave in an earlier posting and must admit I don't fully understand it. I've looked around to see if I can get some help online with subclassing in Freebasic with not much success. Can you extend the code you gave a little to give me more of a pointer.

I've also had a look at http://masm32.com/board/index.php?topic ... 5#msg79165 and downloaded the code and executable. I've run the executable, which does exactly what I want (with one exception, editing the number you can place more than one minus sign at the start of the number e.g. I was able to edit -0.123 with the result -0.123 to ---0.123 with the result 0.0 by successively typing a minus at the very beginning of the number entry). With respect to the code, I have no experience of assembler code so haven't a clue as to how it works.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

The line PrevWinProc=SetWindowLongPtr(Edit_1, GWLP_WNDPROC, @SubEdit) tells the OS that from now on, before doing the default processing of messages, Windows passes by the callback SUB SubEdit. This is a user-defined SUB which receives all messages sent by the OS,together with their wParam and lParam.

We are only interested in the WM_CHAR message:

Code: Select all

Sub SubEdit(ByVal hWnd As HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM)
  Dim as WPARAM wp2
  wp2=wParam
  if uMsg=WM_CHAR then
   print wParam; " ";
   if wParam>57 then wp2=0: print wParam;"? ";
  endif
  CallWindowProc(PrevWinProc, hWnd, uMsg, wp2, lParam)
End Sub
Normally, we ignore the messages and pass them on to Windows via CallWindowProc. However, if we don't like the CHAR passed (e.g. everything above Ascii 57), we set wp2 to zero, so that CallWindowProc passes a null char. The edit control doesn't know what to do with a null char and therefore ignores it completely.

The two prints are for debugging, as you can imagine. What is still needed is the logic which determines whether the char "+" or "x" should be allowed to pass or not. So you need to get the text, determine the current position, and decide whether to allow the char or block it.

Let me know if something is not clear.
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

jj2007
Just running through your code to see what happens and I get 2 warnings both associated with

Code: Select all

PrevWinProc=SetWindowLongPtr(Edit_1, GWLP_WNDPROC, @SubEdit)
1.. warning 2(1): Passing pointer to scalar, at parameter 3 of SETWINDOWLONGPTR()
2.. warning 4(1): Suspicious pointer assignment

I don't know if this has any significance. It doesn't stop Compilation/Execute, but does stop Quickrun.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: Numeric Entry in an EditBox

Post by Josep Roca »

You have to do the appropriate casts, e.g. (for the Passing pointer to scalar warning)

PrevWinProc=SetWindowLongPtr(Edit_1, GWLP_WNDPROC, CAST(LONG_PTR, @SubEdit))
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

Josep's solution will certainly remove these warnings. Fb exaggerates the type checking, the args are perfectly valid.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Numeric Entry in an EditBox

Post by fxm »

See the post I just sent: viewtopic.php?p=251125#p251125
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

Josep Roca wrote:You have to do the appropriate casts, e.g. (for the Passing pointer to scalar warning)

PrevWinProc=SetWindowLongPtr(Edit_1, GWLP_WNDPROC, CAST(LONG_PTR, @SubEdit))
That still gives a warning 4(1): Suspicious pointer assignment. I find this kind of wrong type checking really exaggerated. Why do I need a CAST(SOME_TYPE_OF_POINTER, @Whatever) when it's crystal clear that the ampersand denotes a POINTER...? This is C++ BS, not Basic.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: Numeric Entry in an EditBox

Post by Josep Roca »

> That still gives a warning 4(1): Suspicious pointer assignment.

SetWindowLongPtr returns a long in 32 bit and a LONG_PTR (not a pointer, but a LONGINT) in 64 bit, and it is being assigned to a variable declared as ANY PTR. So you need another cast.

With Free Basic, you cant write sloppy code that passes pointers to scalars and scalars to pointers without casting.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

It returns a pointer to the old wndproc, and expects as arg a pointer to the new wndproc.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: Numeric Entry in an EditBox

Post by Josep Roca »

> It returns a pointer to the old wndproc

But not as a pointer variable but as a scalar.

Try

PrevWinProc = CAST(ANY PTR, SetWindowLongPtr(Edit_1, GWLP_WNDPROC, CAST(LONG_PTR, @SubEdit)))
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

Dim shared as any ptr PrevWinProc ' warning 4(1): Suspicious pointer assignment
Dim shared as LONG_PTR PrevWinProc ' warning 1(1): Passing scalar as pointer, at parameter 1 of CALLWINDOWPROC()

PrevWinProc = CAST(ANY PTR, SetWindowLongPtr(Edit_1, GWLP_WNDPROC, CAST(LONG_PTR, @SubEdit)))
a) with Dim shared as LONG_PTR PrevWinProc ' warning 5(0): Implicit conversion
b) with Dim shared as any ptr PrevWinProc: "OK"

This is really sick! I have no other word for this nonsense. A pointer is a pointer, there is no ambiguity. And SetWindowLongPtr points the OS to a new WndProc.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Numeric Entry in an EditBox

Post by fxm »

Or (only user parameters are converted):
Cast(LONG_PTR, PrevWinProc) = SetWindowLongPtr(Edit_1, GWLP_WNDPROC, CAST(LONG_PTR, @SubEdit))
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: Numeric Entry in an EditBox

Post by Josep Roca »

This is really sick! I have no other word for this nonsense. A pointer is a pointer, there is no ambiguity. And SetWindowLongPtr points the OS to a new WndProc.
I don't see any nonsense, although I agree that strict type casting can be very annoying sometimes. With other compilers such PowerBasic, with relaxed type casting, some complain that the compiler does not warn them when they pass an scalar by mistake to a function that expects a pointer.

Because SetWindowLongPtr is not limited to work with pointer values, but also allows to use scalars, for example to store scalar values in the user data of the control, the third parameter and the return value haven't been declared as pointer but as scalars. Don't forget that the original function name was SetWindowLong (without the "Ptr" part, that was added latter, with 64 bit, to avoid a name conflict). Therefore, the function expects a LONG in 32 bit and a LONGINT in 64 bit, which can also be pointer values because they are the same size.

Code: Select all

declare function SetWindowLongPtr alias "SetWindowLongA"(byval hWnd as HWND, byval nIndex as long, byval dwNewLong as LONG) as LONG
declare function SetWindowLongPtr alias "SetWindowLongPtrA"(byval hWnd as HWND, byval nIndex as long, byval dwNewLong as LONG_PTR) as LONG_PTR
In 32 bit they are LONGs, and in 64 bit LONG_PTR, that despite the misleading "_PTR" in its name, are no pointers but LONGINTs in 64 bit and LONGs in 32 bit.

Therefore, when you use @SubEdit, you are passing a pointer to a parameter declared as LONG, and the compiler warns about passing a wrong type, and when you do "PrevWinProc =", that has been declared as ANY PTR, you are assigning a LONG value to a pointer variable, and the compiler complains about "Implicit conversion", so it needs a "CAST(ANY PTR, " to supress the warning. If you declare PrevWinProc as LONG_PTR, then you don't have to use "CAST(ANY PTR, ".

So it can be annoying, but it makes sense. If Microsodt diden't have tried to use the same function to work both with scalars and pointers they will have avoided this mess. They could have implemented SetWindowLong to work with scalars and SetWindowLongPtr to work with pointers.
Post Reply