Das hat mir natürlich alles wieder keine Ruhe gelassen. Ich habe mir daher den "Pfeifenwichs" (wie Dieter Hallervorden alias Kongo Otto es in "Die Rache der Enterbten" ausgedrückt hätte) mal genauer angesehen. Und es ist natürlich wieder genau das: Pfeifenwichs, also unglaublich komplizierte Windows-API-Programmierung. Aber man kann, ebenfalls wie fast immer, auch fast alles damit anstellen. Zum Beispiel Float-Werte inkrementieren, oder sogar beliebige Strings statt der Zahlen in das SpinEdit schreiben. Das ist bestimmt manchmal einfacher (bei wenigen Auswahlmöglichkeiten), als immer eine ChoiceBox aufklappen und darin herumklicken zu müssen.
Auch wenn ich den Code nachher nicht mehr ändern kann, wenn ich noch einen Fehler finde oder Verbesserungen vornehme, poste ich ihn trotzdem einmal hier:
!
$H Windows.ph
$H Messages.ph
STRUCT S_NMHDR=hwndFrom&,idFrom&,code&
STRUCT S_NMUPDOWN=hwndFrom&,idFrom&,code&,iPos&,iDelta&
declare ende%,hSE%,hUD%,hSE2%,hUD2%,value%,b#,StringsForSE2$[3],AnzStringsForSE2%
SUBCLASSPROC
declare ReturnValue&,b#,OldValue!,NewValue!,StepValue!,code&
declare OldStringVal$,NewStringVal$,i%,val%
ReturnValue&=0
'{ ;%HWnd
if &sWnd=%HWnd
'{ 'WM_NOTIFY
if %sMessage=~WM_NOTIFY
dim b#,S_NMHDR
b#=&slParam
'{ '1. SpinEdit (Float-Werte)
if b#.hwndfrom&=hUD%
if b#.code&=-722 '-722=~UDN_DELTAPOS
StepValue!=1.05
dispose b#
dim b#,S_NMUPDOWN
b#=&slParam
if b#.idelta&>0 'Up-Button clicked (CAVE: Wenn man MaxVal und MinVal falsch herum gesetzt hat, zählen die Pfeile in die falsche Richtung!)
'@sendmessage(hUD%,~UDM_SETPOS32,0,@sendmessage(hUD%,~UDM_GETPOS32,0,0)+1) 'hier können nur Integer-Werte gesetzt werden (aber die Range-Kontrolle übernimmt dann immerhin das UpDown-Control), wir setzen das Edit-Control also vollständig selbst
OldValue!=@val(@gettext$(hSE%))
NewValue!=OldValue!+StepValue!
if NewValue!<-0.0
NewValue!=0.0
elseif NewValue!>100.0
NewValue!=100.0
endif
settext hSE%,@str$(NewValue!)
'~beep(2000,30)
elseif b#.iDelta&<0 'Down-Button clicked
'@sendmessage(hUD%,~UDM_SETPOS32,0,@sendmessage(hUD%,~UDM_GETPOS32,0,0)-1) 'hier können nur Integer-Werte gesetzt werden (aber die Range-Kontrolle übernimmt dann immerhin das UpDown-Control), wir setzen das Edit-Control also vollständig selbst
OldValue!=@val(@gettext$(hSE%))
NewValue!=OldValue!-StepValue!
if NewValue!<-0.0
NewValue!=0.0
elseif NewValue!>100.0
NewValue!=100.0
endif
settext hSE%,@str$(NewValue!)
'~beep(1000,30)
endif
@set("WinProc",0) 'muss sein, weil sonst auch mit return 1 immer noch Windows die Kontrolle über diese Aktion behalten würde und um 1 in-/dekrementieren würde
ReturnValue&=1 '0=UDS_SETBUDDYINT-Style in-/dekrementiert automatisch und überschreibt unsere Änderungen (wenn er bei der Control-Erstellung gesetzt wurde), also <>0 zurückgeben ("wir machen das selbst")
endif
'}
'{ '2. SpinEdit (Strings)
elseif b#.hwndFrom&=hUD2%
if b#.code&=-722 '-722=~UDN_DELTAPOS
dispose b#
dim b#,S_NMUPDOWN
b#=&slParam
if b#.idelta&>0 'Up-Button clicked (CAVE: Wenn man MaxVal und MinVal falsch herum gesetzt hat, zählen die Pfeile in die falsche Richtung!)
for i%,1,AnzStringsForSE2%
if StringsForSE2$[i%]=@gettext$(hSE2%)
val%=i%+1
if val%>AnzStringsForSE2%
val%=1
endif
break
endif
endfor 'i%
settext hSE2%,StringsForSE2$[val%]
'~beep(2000,30)
elseif b#.iDelta&<0 'Down-Button clicked
for i%,1,AnzStringsForSE2%
if StringsForSE2$[i%]=@gettext$(hSE2%)
val%=i%-1
if val%<1
val%=AnzStringsForSE2%
endif
break
endif
endfor 'i%
settext hSE2%,StringsForSE2$[val%]
'~beep(1000,30)
endif
@set("WinProc",0) 'muss sein, weil sonst auch mit return 1 immer noch Windows die Kontrolle über diese Aktion behalten würde und um 1 in-/dekrementieren würde
ReturnValue&=1 '0=UDS_SETBUDDYINT-Style in-/dekrementiert automatisch und überschreibt unsere Änderungen (wenn er bei der Control-Erstellung gesetzt wurde), also <>0 zurückgeben ("wir machen das selbst")
endif
'}
endif
dispose b#
'}
endif
'}
endif
return ReturnValue&
ENDPROC
windowstyle 1+2+4+8+512
cls
usermessages $10
@set("Decimals",2)
hSE%=~CreateWindowEx(~WS_EX_CLIENTEDGE,"EDIT","",~WS_CHILD | ~WS_VISIBLE | ~ES_RIGHT | ~WS_TABSTOP,50,30,90,22,%HWnd,1,%HInstance,0) ' | ~ES_NUMBER - nein, dann können keine negativen Zahlen und keine Dezimalzahlen eingegeben werden (diese Limits könnte man entsprechend im Subclassing abfangen, wenn man wollte, aber das sprengt hier den Rahmen)
hUD%=~CreateWindowEx(0,"msctls_updown32",0,~WS_CHILD | ~WS_VISIBLE | 4 | 2 | 32,0,0,0,0,%HWnd,2,%HInstance,0) 'erstellt das UpDown-Control
'UDS_SETBUDDYINT (2) = setzt den Wert direkt im Edit-Control - wenn man andere Schrittweiten als 1 will, darf dieser Style nicht gesetzt sein (oder im Subclassing WinProc auf 0 setzen *und* <>0 zurückgeben), dann muss man mit Subclassing von hWndParent die Notification UDN_DELTAPOS auswerten und das Editfeld selbst bestücken
'UDS_ALIGNRIGHT (4) = rechts im Edit-Feld (dieses wird automatisch entsprechend verkleinert, um die Pfeil-Buttons aufzunehmen)
'UDS_ARROWKEYS (32) = das UpDown-Control verarbeitet die hoch-/runter-Tasten, wenn der Fokus auf dem verknüpften Edit-Control liegt (es wird dadurch UDN_DELTAPOS ausgelöst, genau wie bei Mausklicks auf die Pfeilbuttons)
'UDS_SETBUDDYINT (16) = de-/inkrementiert das Edit-Control automatisch (hier nicht benutzt, weil wir Float-Werte benutzen wollen)
'{ 'alle UDS-Stile
/*
UDS_ALIGNLEFT
Positions the up-down control next to the left edge of the buddy window. The buddy window is moved to the right, and its width is decreased to accommodate the width of the up-down control.
UDS_ALIGNRIGHT
Positions the up-down control next to the right edge of the buddy window. The width of the buddy window is decreased to accommodate the width of the up-down control.
UDS_ARROWKEYS
Causes the up-down control to increment and decrement the position when the UP ARROW and DOWN ARROW keys are pressed.
UDS_AUTOBUDDY
Automatically selects the previous window in the z-order as the up-down control's buddy window.
UDS_HORZ
Causes the up-down control's arrows to point left and right instead of up and down.
UDS_HOTTRACK
Causes the control to exhibit "hot tracking" behavior. That is, it highlights the UP ARROW and DOWN ARROW on the control as the pointer passes over them. This style requires Windows 98 or Windows 2000. If the system is running Windows 95 or Windows NT 4.0, the flag is ignored. To check whether hot tracking is enabled, call SystemParametersInfo.
UDS_NOTHOUSANDS
Does not insert a thousands separator between every three decimal digits.
UDS_SETBUDDYINT
Causes the up-down control to set the text of the buddy window (using the WM_SETTEXT message) when the position changes. The text consists of the position formatted as a decimal or hexadecimal string.
UDS_WRAP
Causes the position to "wrap" if it is incremented or decremented beyond the ending or beginning of the range.
*/
'}
@sendmessage(hUD%,1129,hSE%,0) '1129=~UDM_SETBUDDY - verknüpft das Edit-Control mit dem UpDown-Control
@sendmessage(hUD%,1135,0,100) '1135=~UDM_SETRANGE32; Min 0, Max 100 - CAVE: Wenn man die Werte vertauscht, zählen die Pfeile falschherum (Up-Arrow: -1, Down-Arrow: +1). In diesem Beispiel überschreiben wir alle Automatismen in der SubclassProc, weil wir Float-Werte inkrementieren wollen, diese Zeile dient daher nur der Demonstration. - Nach Erstellung des UD-Controls sind die Pfeile erst einmal falsch herum gepolt!
@sendmessage(hUD%,1127,0,50) '1127=~UDM_SETPOS; Startwert - Ist hier ebenfalls nur um der Demonstration willen, da wir einen Float-Wert setzen wollen, was mit einem nativ arbeitenden SpinEdit nicht geht:
settext hSE%,"50.00"
value%=@sendmessage(hUD%,1138,0,0) '1138=~UDM_GETPOS32 - kann nur Integer-Zahlen verarbeiten!
print "Anfangswert SpinEdit Nr. 1="+@str$(value%)+" (hier falsch (Maximum), weil keine Integer-Zahl)" 'gibt hier einen falschen Wert zurück, weil im SpinEdit keine Integer-Zahl steht
subclass %HWnd,1 'müsste bei der sehr oft verwendeten Schrittweite 1 nicht sein, machen wir hier aber so, um das "volle Programm" zu demonstrieren (Float-Inkrementierung und Strings)
hSE2%=~CreateWindowEx(~WS_EX_CLIENTEDGE,"EDIT","",~WS_CHILD | ~WS_VISIBLE | ~WS_TABSTOP,50,60,120,22,%HWnd,1,%HInstance,0) ' | ~ES_RIGHT
hUD2%=~CreateWindowEx(0,"msctls_updown32",0,~WS_CHILD | ~WS_VISIBLE | 4 | 32,0,0,0,0,%HWnd,2,%HInstance,0) 'erstellt das UpDown-Control
@sendmessage(hUD2%,1129,hSE2%,0) '1129=~UDM_SETBUDDY
@sendmessage(hUD2%,1135,0,1) '1135=~UDM_SETRANGE32; müssen wir machen, obwohl wir gar keine Zahlen verarbeiten wollen, damit die Pfeile in die richtige Richtung wirken (es kommt hier nur auf die Richtung an, die Werte an sich sind egal) - Nach Erstellung des UD-Controls sind die Pfeile erst einmal falsch herum gepolt!
AnzStringsForSE2%=3
StringsForSE2$[1]="Teststring 1"
StringsForSE2$[2]="Teststring 2"
StringsForSE2$[3]="Teststring 3"
settext hSE2%,StringsForSE2$[1]
ende%=0
whilenot ende%
waitinput
if @iskey(27) or (%uMessage=$10)
ende%=1
while @iskey(27)
sleep 25
endwhile
endif
endwhile
subclass %HWnd,0
usermessages -$10
end
Alles anzeigen