[B3D] Fake Fenster

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

Eingeproggt

Betreff: [B3D] Fake Fenster

BeitragDi, Jul 20, 2010 21:50
Antworten mit Zitat
Benutzer-Profile anzeigen
Guten Abend!

Als "Nebenprodukt" meiner Spielerein im Urlaub für meinen Messenger kam ein kleiner Code heraus der mit allerhand WinAPI-Gehacke mehrere Fenster "simuliert".

Also das ganze ist n bissi ein Fake, daher auch der Titel. Es gibt nach wie vor nur ein Graphics Fenster (welches übrigens von meiner Lib hier verwaltet wird) und von dem werden halt bestimmte Ausschnitte (Regionen) angezeigt.
Man kann damit und etwas weiterghender Spielerei (beispielsweise eigener GUI) mehrere Fenster in B3D darstellen.

Aber nochmal, das Ganze spielt sich auf einem Graphikbuffer ab, daher gibt es Probleme beim Überlappen von "Fenstern"... ich möchte hier nur die Grundlage anbieten, keine Komplettlösung. Je nach verwendeter GUI werdet ihr da selber noch einiges zu managen haben.

Hier die Funktionssammlung:

BlitzBasic: [AUSKLAPPEN]
;Regions-Include
;von Christoph Mach - Juli 2010

;--- Beschreibung

;Mithilfe dieser Funktionssammlung kann man "Regionen" auf dem Desktop erstellen die die Illusion vermitteln können, dass mehrere Fenster geöffnet wären.
;"Backstage" gibt es nur einen Graphik-Buffer (wie gewohnt) von dem nur Ausschnitte gezeigt werden.
;Die "Illusion" der mehreren Fenster wird perfektioniert durch ebenfalls enthaltenem Drag&Drop
;Allerdings ergeben sich Probleme, wenn Regionen überlappen (zB dass dann mehrere Buttons übereinander liegen und gleichzeitig gedrüct werden würden)
;Diese Besonderheiten muss jeder selbst in den Griff kriegen und für seine Anwendung passend regeln.

;--- Zielgruppe

;Die Verwendung dieser Funktionssammlung macht vor allem Sinn wenn zB ein Tool mit graphischer Bedienungsoberfläche im Fenstermodus laufen soll und weitere Fenster gebraucht werden.
;Es werden Grundkenntnisse von userlibs benötigt (wie man sie einbindet) sowie etwas "Kooperativität" mit dem Regionen-Type (der Koordinaten und Größe der Regionen enthält)
;Klarerweise ist diese Lib nicht an B+ Bneutzer gerichtet, da die ohnehin Funktionen zum Erstellen neuer Fenster haben.
;Außerdem wird beim Initiieren der Lib (mittels "SetWindowedFullscreen") der Fenster-Graphikmodus gesetzt welcher erforderlich ist. Es muss / DARF daher im Anshcluss daran kein weiterer Graphics-Aufruf folgen.

;--- Verwendete WinAPI-Funktionen (Links nur angeführt, falls man weitere Infos sucht)

;Userlibs können von hier bezogen werden:
;https://www.blitzforum.de/forum/viewtopic.php?t=7330
;Entweder ihr sucht selber, welche ihr nun braucht oder ihr kopiert euch gleich alle (empfohlen Wink )

;SystemParametersInfo: http://msdn.microsoft.com/en-us/library/ms724947(VS.85).aspx
;SetWindowPos: http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx
;SetWindowRgn: http://msdn.microsoft.com/en-us/library/dd145102(VS.85).aspx
;CombineRgn: http://msdn.microsoft.com/en-us/library/dd183465(VS.85).aspx
;CreateRectRgn: http://msdn.microsoft.com/en-us/library/dd183514(VS.85).aspx
;CreateRoundRectRgn: http://msdn.microsoft.com/en-us/library/dd183516(v=VS.85).aspx
;DeleteObject: http://msdn.microsoft.com/en-us/library/dd183539(VS.85).aspx
;GetSystemMetrics: http://msdn.microsoft.com/en-us/library/ms724385(VS.85).aspx
;GetCursorPos: http://msdn.microsoft.com/en-us/library/ms648390(VS.85).aspx

Type region
Field x,y,w,h
Field radius
Field id
End Type

;Globals

Global main_region

Global drag_rgn.region
Global drag_x,drag_y
Global mouse_x,mouse_y

Global gfx_w,gfx_h
Global gfx_off_x,gfx_off_y
Global hwnd

;Setup - beinhaltet bereits Graphics!
SetWindowedFullscreen()

;Funktionen

;Anmerkung:
;Klar wäre es günstiger, mit den bestehenden Region-Handles zu arbeiten
;aber leider funktionierte das nie so richtig...
;deshalb werden in den folgenden Funktionen alle Regionen immer komplett neu erstellt

;Graphics so einstellen, dass Bereich sich genau mit dem Destop deckt
;dies ist dann der Bereich, wo wir unsere Regionen ("Fake Fenster") darstellen und steuern.
Function SetWindowedFullscreen()
;Desktop-Abmessungen
Local bank=CreateBank(16)
api_SystemParametersInfo($0030,0,bank,0)
Local x=PeekInt(bank,0)
Local y=PeekInt(bank,4)
Local x2=PeekInt(bank,8)
Local y2=PeekInt(bank,12)
FreeBank bank

;Graphics
gfx_w=x2-x
gfx_h=y2-y
Graphics gfx_w,gfx_h,0,2
hwnd=SystemProperty("AppHWND")

;Fenster so verschieben, dass Graphics-Bereich genau links oben am Bildschirm anfängt
;(und da er so groß ist wie der Desktop diesen nun genau umfasst)
gfx_off_x=api_GetSystemMetrics(7)
gfx_off_y=api_GetSystemMetrics(4)+api_GetSystemMetrics(8)
api_SetWindowPos(hwnd,0,-gfx_off_x,-gfx_off_y,0,0,1)
End Function

Const COMPLEXREGION = 3
Const SIMPLEREGION = 2
Const NULLREGION = 1
Const ERRORAPI = 0

Const RGN_AND = 1
Const RGN_COPY = 5
Const RGN_DIFF = 4
Const RGN_OR = 2
Const RGN_XOR = 3

Const WINDING = 2
Const ALTERNATE = 1

;Neue Region erstellen (bzw. zu bereits bestehenden hinzufügen)
;Parameter x und y geben die Koordinaten vom Desktop-Ursprung aus an
;Wenn ein Radius größer als 0 angegeben wird, werden Regionen mit abgerundeten Ecken erzeugt
Function AddRegion.region(x,y,w,h,radius=0)
FreeRegions()
;Neu erstellen
Local ret.region=New region
ret\x=x
ret\y=y
ret\w=w
ret\h=h
ret\radius=radius
Insert ret Before First region
CreateMainRegion()
api_SetWindowRgn(hwnd,main_region,True)
Return ret
End Function

;Region aus dem "Verbund" entfernen
;Parameter "behave" wenn letztes Fesnter geschlossen:
Const LASTREGION_BEHAVE_NONE=0 ;das letzte Fenster wird nicht geschlossen
Const LASTREGION_BEHAVE_RESTORE=1 ;Gesamten Graphics-Screen wiederherstellen (Größe von Desktop)
Const LASTREGION_BEHAVE_INVISIBE=2 ;Keine Graphikdarstellung, Programm läuft jedoch weiter (im Hintergrund)
Const LASTREGION_BEHAVE_CLOSE=3 ;Programm beenden
;Es wird (außer bei CLOSE) 0 zurückgeliefert, wenn das letzte Fenster geschlossen wurde (sonst 1)
Function RemoveRegion(target.region,behave=LASTREGION_BEHAVE_CLOSE)
If target=Null Then Return 0
If After target=Null And Before target=Null And behave=LASTREGION_BEHAVE_NONE Then Return 0
FreeRegions()
;Wenn die letzte Region gelöscht wird, Original-Graphics wiederherstellen oder
If After target=Null And Before target=Null Then
Select behave
Case LASTREGION_BEHAVE_RESTORE
main_region=api_CreateRectRgn(0+gfx_off_x,0+gfx_off_y,gfx_w+gfx_off_x,gfx_h+gfx_off_y)
api_SetWindowRgn(hwnd,main_region,True)
Case LASTREGION_BEHAVE_INVISIBE
main_region=api_CreateRectRgn(0,0,0,0)
api_SetWindowRgn(hwnd,main_region,True)
Case LASTREGION_BEHAVE_CLOSE
End
End Select
Delete target
Return 0
EndIf
Delete target
CreateMainRegion()
api_SetWindowRgn(hwnd,main_region,True)
Return 1
End Function

;Positioniert eine Region um, indem alle Regionen neu erstellt werden
Function SetRegionPosition(target.region,x,y)
If target=Null Then Return 0
FreeRegions()
;Änderung
target\x=x
target\y=y
CreateMainRegion()
api_SetWindowRgn(hwnd,main_region,True)
Return 1
End Function

;Alle Regionen freigeben
Function FreeRegions()
Local rgn.region
If main_region<>0 Then api_DeleteObject(main_region)
For rgn=Each region
api_DeleteObject(rgn\id)
Next
End Function

;Alle Regionen zu einer zusammen fassen
Function CreateMainRegion()
;Alle Regionen neu erzeugen
Local rgn.region
For rgn=Each region
If rgn\radius>0 Then
rgn\id=api_CreateRoundRectRgn(rgn\x+gfx_off_x,rgn\y+gfx_off_y,rgn\w+rgn\x+gfx_off_x+1,rgn\h+rgn\y+gfx_off_y+1,rgn\radius,rgn\radius) ;Fragt mich nicht, warum hier +1 bei der Größe gehört...
Else
rgn\id=api_CreateRectRgn(rgn\x+gfx_off_x,rgn\y+gfx_off_y,rgn\w+rgn\x+gfx_off_x,rgn\h+rgn\y+gfx_off_y)
EndIf
Next
;Zusammenfassen
rgn.region=First region
Local rgn2.region=rgn
main_region=rgn\id
Local temp,result
Repeat
rgn2=After rgn2
If rgn2=Null Then Exit
;Immer eine Region zum bestehendem Komplex dazu nehmen
temp=api_CreateRectRgn(0,0,0,0)
result=api_CombineRgn(temp,main_region,rgn2\id,RGN_OR)
If result<>NULLREGION And result<>ERRORAPI Then
api_DeleteObject(main_region)
main_region=temp
EndIf
Forever
End Function

;Funktionen, um Regionen mit Maus zu ziehen
Function StartDragRegion(rgn.region)
If drag_rgn=Null Then
GetGlobalMouse()
drag_rgn=rgn
drag_x=mouse_x-rgn\x
drag_y=mouse_y-rgn\y
EndIf
End Function

Function DragRegion(autostop=True)
If drag_rgn<>Null Then
GetGlobalMouse()
SetRegionPosition(drag_rgn,mouse_x-drag_x,mouse_y-drag_y)
If autostop Then
If Not MouseDown(1) Then StopDragRegion()
EndIf
EndIf
End Function

Function StopDragRegion()
drag_rgn=Null
End Function

Function GetGlobalMouse()
Local bank=CreateBank(8)
api_GetCursorPos(bank)
mouse_x=PeekInt(bank,0)
mouse_y=PeekInt(bank,4)
FreeBank bank
End Function


und ein Beispiel dazu:

BlitzBasic: [AUSKLAPPEN]
;Regionen-Demo

Include "Regionen.bb"

SetBuffer BackBuffer()

;Erstes "Fnester" erstellen
Local main.region=AddRegion((gfx_w-120)/2,(gfx_h-70)/2,120,70,20)

;Vars für die Demo
Global mx,my,mhit
Local rgn.region
Local timer=CreateTimer(50)

;Hauptschleife
Repeat
mx=MouseX()
my=MouseY()
mhit=MouseHit(1)

;Muss immer ausgeführt werden, man beachte den Parameter "autostop":
;Wenn true (Standard), dann wird der Dragvorgang beim Loslassen der linken Maustaste gestoppt
;Wird die Bedienung anders designt, so muss dafür Sorge getragen werden, dass "StopDragRegion" aufgerufen wird
DragRegion()

;Alle Regionen zeichnen sowie verschiebbar (linke Maustaste gedrückt halten)
;und entfernbar (rechte Maustaste klicken) machen.
For rgn=Each region
If rgn<>main Then
Rect rgn\x,rgn\y,rgn\w,rgn\h,0
Text rgn\x+rgn\w/2,rgn\y+10,"Drag me!",1
If mx>rgn\x And mx<rgn\x+rgn\w And my>rgn\y And my<rgn\y+rgn\h Then
If MouseDown(1) Then
StartDragRegion(rgn) ;Drag starten wann auch immer gewünscht
EndIf
EndIf

If Button(rgn\x+10,rgn\y+30,"Schließen") Then
RemoveRegion(rgn)
EndIf
EndIf
Next

If Button(main\x+10,main\y+10,"Neues Fenster") Then
temp2.region=AddRegion(main\x,main\y+main\h,120,60)
EndIf

If Button(main\x+10,main\y+40,"Beenden") Then
End
EndIf

Flip 0:Cls
WaitTimer timer
Until KeyHit(1)
End

Function Button(x,y,txt$)
Rect x,y,100,20,0
Text x+50,y+10,txt$,1,1
If mx>x And mx<x+100 And my>y And my<y+20 Then
Rect x+1,y+1,98,18,0
If mhit Then
mhit=False
Return True
EndIf
EndIf
Return False
End Function


Wie schon geschrieben, läuft da vieles über die WinAPI - das einbinden der verlinkten USerlibs würde ich euch bitten selbst zu können...
Ich kann für alle die kein B3D haben auch mal das Beispiel kompilieren.

Zum Abschluß noch ein kleines Danke an the freak der ich in gewisser Maßen auf die Idee brachte Wink

mfG, Christoph.

PS: Mir ist bewußt dass dieser Code am Anfang irgendwie zu nichts taugt und viel zu spezifisch ist... ja er benötigt Einarbeitungszeit aber ich hoffe schon bald im Rahmen meines Projektes für das der Code eigentlich entstand zeigen zu können was damit möglich ist Wink
Gewinner des BCC 18, 33 und 65 sowie MiniBCC 9

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group