YAED - Yet another Event Dispatcher

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

YAED - Yet another Event Dispatcher

Beitrag von Blackskyliner »

YAED - Yet Another Event Dispatcher

Beschreibung:
Angefangen hat das ganze Projekt damit, das ich ein Thread-Safe Messaging System basteln wollte, um z.B. veränderungen an Gadgets aus Thread heraus anzeigen zu können.
Da man Gadgets nur aus dem erstellenden Thread heraus behandeln soll, habe ich mir gedacht, dann mach ich mir halt eine Liste, wo einzelne Nachrichten gespeichert werden.
Diese werden z.B. in einem Child-Thread zu der Liste hinzugefügt um dann entsprechend im Main-Thread verarbeitet zu werden.

Als dieses System fertig war, hab ich mir gedach, man kann auf diesem System aufbauend auch einen FunktionsDispatcher basteln, so wie man das von anderen Sprachen her kennt.
Also habe ich angefangen die dispatcher.pbi zu schreiben, welche letztendlich eine Funktion entsprechnd in einem anderen Thread ausführen lassen kann.
z.B. eine Funktion die im 1. Fenster was vom Mainthread erstellt wurde, Gadgets neu anordnen soll auf Knopfdruck eines Gadgets aus einem Fenster das in einem Child-Thread erzeugt wurde.

Als das alles fertig war, dachte ich mir, da diese Funktionalität (in meiner Sichtweise) sehr auf ein Event-Driven System hinweist, dachte ich mir: "Fehlt ja nurnoch ein Gadget EventSystem"
Dies habe ich dann als nächstes geschrieben.

Letztendlich kann man nun mit diesen 3 Libarys wunderbar ein Event-Driven User Interface zusammen basteln. (Alla VistualStudio)

Außerdem kann dieses System auch mit mehreren Fenstern umgehen, da man dann nur ein eigenen EventMessage Loop definieren muss (ID-Technisch) und entsprechend aufrufen.
Das tolle an diesem System istaußerdem das alle Gadgets, die via EventGadget() verwaltet werden sofort benutzt werden können.

Hier der entsprechende Quellcode der einzelnen Includes und am Ende das Beispiel

multiDatatype.pbi

Code: Alles auswählen

; Multitype datatype for easy usage multiple datatypes
; like parameter for function arrays @see(threadMessaging.pbi)

; License: MIT-License
; Copyright (c) 2010 Blackskyliner
; 
; Permission is hereby granted, free of charge, To any person
; obtaining a copy of this software And associated documentation
; files (the "Software"), To deal in the software without
; restriction, including without limitation the rights To use,
; copy, modify, merge, publish, distribute, sublicense, And/or sell
; copies of the software, And To permit persons To whom the
; software is furnished To do so, subject To the following
; conditions:
; 
; the above copyright notice And this Permission notice shall be
; included in all copies Or substantial portions of the software.
; 
; the software is PROVIDED "AS IS", without WARRANTY of any KIND,
; EXPRESS Or IMPLIED, including BUT Not LIMITED To the WARRANTIES
; of MERCHANTABILITY, FITNESS For a PARTICULAR PURPOSE And
; NONINFRINGEMENT. in NO event shall the AUTHORS Or copyright
; holders be LIABLE For any CLAIM, DAMAGES Or OTHER LIABILITY,
; WHETHER in AN ACTION of CONTRACT, TORT Or OTHERWISE, ARISING
; FROM, OUT of Or in CONNECTION With the software Or the use Or
; OTHER DEALINGS in the software.

Structure t_multiDatatype
	type.l ; #PB_Integer, #PB_String, ...
	StructureUnion 
		integer.i
		long.l
		double.d
		
		float.f
		quad.q
		
		byte.b
		ascii.a
		character.c
		word.w
		unicode.u
		
		*pointer
	EndStructureUnion
	string.s
EndStructure

Structure t_multiDatatypeArrayArgument
  Index.t_multiDatatype[0]
EndStructure

Procedure createLongMessage(*temp.t_multiDatatype, dataVar.l)
	*temp\long = dataVar
	*temp\type = #PB_Long
EndProcedure

Procedure createDoubleMessage(*temp.t_multiDatatype, dataVar.d)
	*temp\double = dataVar
	*temp\type = #PB_Double
EndProcedure

Procedure createIntegerMessage(*temp.t_multiDatatype, dataVar.i)
	*temp\integer = dataVar
	*temp\type = #PB_Integer
EndProcedure

Procedure createFloatMessage(*temp.t_multiDatatype, dataVar.f)
	*temp\float = dataVar
	*temp\type = #PB_Float
EndProcedure

Procedure createQuadMessage(*temp.t_multiDatatype, dataVar.q)
	*temp\quad = dataVar
	*temp\type = #PB_Quad
EndProcedure

Procedure createAsciiMessage(*temp.t_multiDatatype, dataVar.a)
	*temp\ascii = dataVar
	*temp\type = #PB_Ascii
EndProcedure

Procedure createWordMessage(*temp.t_multiDatatype, dataVar.w)
	*temp\word = dataVar
	*temp\type = #PB_Word
EndProcedure

Procedure createCharacterMessage(*temp.t_multiDatatype, dataVar.c)
	*temp\character = dataVar
	*temp\type = #PB_Character
EndProcedure

Procedure createStringMessage(*temp.t_multiDatatype, dataVar.s)
	*temp\string = dataVar
	*temp\type = #PB_String
EndProcedure

Procedure createByteMessage(*temp.t_multiDatatype, dataVar.b)
	*temp\byte = dataVar
	*temp\type = #PB_Byte
EndProcedure

Procedure createPointerMessage(*temp.t_multiDatatype, *dataVar)
 	*temp\pointer = *dataVar
 	*temp\type = #PB_Function
EndProcedure

Procedure createUnicodeMessage(*temp.t_multiDatatype, dataVar.u)
	*temp\unicode = dataVar
	*temp\type = #PB_Unicode
EndProcedure
memory.pbi

Code: Alles auswählen

; Memory Wrapper
; Overview over allocated data

; Needs: No dependencies

; Note:
; As of Purebasic 4.50 x86 while running a linux machine with activated Purfier
; there will be an IMA (debugger) when returning allocated memory while having a string as
; a procedure parameter. @see(http://forums.purebasic.com/german/viewtopic.php?f=20&t=22630)

; License: MIT-License
; Copyright (c) 2010 Blackskyliner
; 
; Permission is hereby granted, free of charge, To any person
; obtaining a copy of this software And associated documentation
; files (the "Software"), To deal in the software without
; restriction, including without limitation the rights To use,
; copy, modify, merge, publish, distribute, sublicense, And/or sell
; copies of the software, And To permit persons To whom the
; software is furnished To do so, subject To the following
; conditions:
; 
; the above copyright notice And this Permission notice shall be
; included in all copies Or substantial portions of the software.
; 
; the software is PROVIDED "AS IS", without WARRANTY of any KIND,
; EXPRESS Or IMPLIED, including BUT Not LIMITED To the WARRANTIES
; of MERCHANTABILITY, FITNESS For a PARTICULAR PURPOSE And
; NONINFRINGEMENT. in NO event shall the AUTHORS Or copyright
; holders be LIABLE For any CLAIM, DAMAGES Or OTHER LIABILITY,
; WHETHER in AN ACTION of CONTRACT, TORT Or OTHERWISE, ARISING
; FROM, OUT of Or in CONNECTION With the software Or the use Or
; OTHER DEALINGS in the software.

Global _AllocatedCounter.l = 0
Global _AllocatedCounterMutex.l = CreateMutex()

Procedure _AllocateMemoryWrapper(Size.l, File.s, Line.l)
	Debug File+"["+Str(Line)+"]: Memory allocated."
	LockMutex(_AllocatedCounterMutex);>
		_AllocatedCounter = _AllocatedCounter + 1
	UnlockMutex(_AllocatedCounterMutex);<
	ProcedureReturn AllocateMemory(Size)
EndProcedure

Procedure _FreeMemoryWrapper(address.i, File.s, Line.l)
	Debug File+"["+Str(Line)+"]: Memory freed."
	LockMutex(_AllocatedCounterMutex);>
		_AllocatedCounter = _AllocatedCounter - 1
	UnlockMutex(_AllocatedCounterMutex);<
	FreeMemory(address)
EndProcedure

Macro AllocateMemory_(Size)
	_AllocateMemoryWrapper(Size, #PB_Compiler_File, #PB_Compiler_Line)
EndMacro

Macro FreeMemory_(address)
	_FreeMemoryWrapper(address, #PB_Compiler_File, #PB_Compiler_Line)
EndMacro

Macro ShowAllocatedMemoryCount()
	LockMutex(_AllocatedCounterMutex);>
		Debug _AllocatedCounter
	UnlockMutex(_AllocatedCounterMutex);<
EndMacro
threadMessaging.pbi

Code: Alles auswählen

; Thread Messaging Library
; Multithread-Safe

; Needs: 	multiDatatype.pbi
;			memory.pbi

; License: MIT-License
; Copyright (c) 2010 Blackskyliner
; 
; Permission is hereby granted, free of charge, To any person
; obtaining a copy of this software And associated documentation
; files (the "Software"), To deal in the software without
; restriction, including without limitation the rights To use,
; copy, modify, merge, publish, distribute, sublicense, And/or sell
; copies of the software, And To permit persons To whom the
; software is furnished To do so, subject To the following
; conditions:
; 
; the above copyright notice And this Permission notice shall be
; included in all copies Or substantial portions of the software.
; 
; the software is PROVIDED "AS IS", without WARRANTY of any KIND,
; EXPRESS Or IMPLIED, including BUT Not LIMITED To the WARRANTIES
; of MERCHANTABILITY, FITNESS For a PARTICULAR PURPOSE And
; NONINFRINGEMENT. in NO event shall the AUTHORS Or copyright
; holders be LIABLE For any CLAIM, DAMAGES Or OTHER LIABILITY,
; WHETHER in AN ACTION of CONTRACT, TORT Or OTHERWISE, ARISING
; FROM, OUT of Or in CONNECTION With the software Or the use Or
; OTHER DEALINGS in the software.

XIncludeFile "multiDatatype.pbi"
XIncludeFile "memory.pbi"

Structure t_message
	; The Event that needs to be proccessed
	; This one defines which data are in *eventData
	eventCode.i
	
	; The Data itself. (Dynamically allocated)
	; You need to free them manually...
	*eventData
	
	; To differ the diffrent peek methods
	; use of #PB_ Types
	dataType.i
	
	; #TRUE if it needs to be freed (autmotatically)
	needToBeFreed.i
	
	; Should it be deleted after Called?
	; Manly for Eventsystems which want to register permanent callbacks
	permanent.l
	
	; So we can use GetMessage() in a while loop
	; #True if called
	; #False if needs to be called
	wasCalled.l
EndStructure

Prototype MessageCallbackProc(*message.t_message)

Structure t_MessageCallback
	*funcPointer.MessageCallbackProc
	messagEventID.l
	
	; For easy unregistering...
	; Like t_message.wasCalled
	wasChecked.l
EndStructure

; Global List and thread mutex
; to ensure threadsafety.
Global NewList ThreadEventMessageList.t_message()
Global ThreadEventMessageMutex.i = CreateMutex()
Global NewList ThreadEventMessageCallbackList.t_MessageCallback()
Global ThreadEventMessageCallbackMutex.i = CreateMutex()

; Inserts the given data in the event stack
Procedure CreateMessage(code.l, *eventData.l, dataType.l, dynamic.l = #True, permanent.l = #False)
	Protected Index.l = -1 ; old index to restore
	LockMutex(ThreadEventMessageMutex) ;>
		Index = ListIndex(ThreadEventMessageList())
		LastElement(ThreadEventMessageList())
		AddElement(ThreadEventMessageList())
		ThreadEventMessageList()\dataType = dataType;
		ThreadEventMessageList()\eventCode = code;
		ThreadEventMessageList()\eventData = *eventData;
		ThreadEventMessageList()\needToBeFreed = dynamic
		ThreadEventMessageList()\permanent = permanent
		If Index <> -1
			SelectElement(ThreadEventMessageList(), Index)
		EndIf
	UnlockMutex(ThreadEventMessageMutex) ;<
EndProcedure

; Get the top element of the event stack
Procedure GetMessages(*temp.t_message)
	Protected retVar.b = #False
	LockMutex(ThreadEventMessageMutex) ;>
		If FirstElement(ThreadEventMessageList()) <> 0
			While ThreadEventMessageList()\wasCalled
				If NextElement(ThreadEventMessageList()) = 0
					UnlockMutex(ThreadEventMessageMutex)
					ProcedureReturn #False
				EndIf
			Wend
			
			*temp\dataType = ThreadEventMessageList()\dataType
			*temp\eventCode = ThreadEventMessageList()\eventCode
			*temp\eventData = ThreadEventMessageList()\eventData
			*temp\needToBeFreed = ThreadEventMessageList()\needToBeFreed
			*temp\permanent = ThreadEventMessageList()\permanent
			
			ThreadEventMessageList()\wasCalled = #True
			retVar = #True
			
		EndIf
	UnlockMutex(ThreadEventMessageMutex) ;<
	
	ProcedureReturn retVar
EndProcedure

Procedure DeleteMessage(*message.t_message)
	;CallDebugger
	If *message\needToBeFreed = #True
		FreeMemory_(*message\eventData); free the dynamic data
	EndIf
	; The other data is automatically freed.
EndProcedure

Procedure registerMessageEventCallback(eventID.l, *callback)
	LockMutex(ThreadEventMessageCallbackMutex);>
		LastElement(ThreadEventMessageCallbackList())
		AddElement(ThreadEventMessageCallbackList())
		ThreadEventMessageCallbackList()\funcPointer = *callback
		ThreadEventMessageCallbackList()\messagEventID = eventID
	UnlockMutex(ThreadEventMessageCallbackMutex);<
EndProcedure

Procedure MessageEvent(eventID.l)
	Protected temp.t_message
	Protected calledOnce.l = #False
	
	While GetMessages(@temp)
		calledOnce = #False
		
		LockMutex(ThreadEventMessageCallbackMutex);>
			ResetList(ThreadEventMessageCallbackList())
			While NextElement(ThreadEventMessageCallbackList())
				If ThreadEventMessageCallbackList()\messagEventID = eventID
					ThreadEventMessageCallbackList()\funcPointer(temp)
					calledOnce = #True
				EndIf
			Wend
		UnlockMutex(ThreadEventMessageCallbackMutex);<
		
		;CallDebugger
		If calledOnce And ThreadEventMessageList()\permanent = #False
			LockMutex(ThreadEventMessageMutex);>
				DeleteElement(ThreadEventMessageList())
			UnlockMutex(ThreadEventMessageMutex);<
			
			; Done with the Message so free the dynamically allocated message data
			DeleteMessage(@temp)
		EndIf
		
	Wend
	
	; Reset wasCalled
	LockMutex(ThreadEventMessageMutex);>
		ResetList(ThreadEventMessageList())
		While NextElement(ThreadEventMessageList())
			ThreadEventMessageList()\wasCalled = #False	
		Wend
	UnlockMutex(ThreadEventMessageMutex);<
EndProcedure

; If #PB_Any and FuncPointer = #Null, all Callbacks will be deleted
; If only #PB_Any and FuncPointer is Valid, all Callbacks to this function will be deleted
; If eventID is specified but the FuncPointer is #Null, all Callbacks to this EventId will be deleted
Procedure unregisterMessageEventCallback(eventID.l, *callback)
	Protected temp.t_message
	Protected calledOnce.l = #False
	
	LockMutex(ThreadEventMessageCallbackMutex);>
		While FirstElement(ThreadEventMessageCallbackList())
			While ThreadEventMessageCallbackList()\wasChecked
				If NextElement(ThreadEventMessageCallbackList()) = 0
					
					ResetList(ThreadEventMessageCallbackList())
					While NextElement(ThreadEventMessageCallbackList())
						ThreadEventMessageCallbackList()\wasChecked = #False	
					Wend
					UnlockMutex(ThreadEventMessageCallbackMutex)
					ProcedureReturn
				EndIf
			Wend
			
			ThreadEventMessageCallbackList()\wasChecked = #True
			If eventID = #PB_Any Or eventID = ThreadEventMessageCallbackList()\messagEventID
				If *callback = #Null Or *callback = ThreadEventMessageCallbackList()\funcPointer					
					DeleteElement(ThreadEventMessageCallbackList())
				EndIf
			EndIf
		Wend
	UnlockMutex(ThreadEventMessageCallbackMutex);<
EndProcedure
dispatcher.pbi

Code: Alles auswählen

; Function Dispatcher Library

; Needs: 	threadMessaging.pbi

; License: MIT-License
; Copyright (c) 2010 Blackskyliner
; 
; Permission is hereby granted, free of charge, To any person
; obtaining a copy of this software And associated documentation
; files (the "Software"), To deal in the software without
; restriction, including without limitation the rights To use,
; copy, modify, merge, publish, distribute, sublicense, And/or sell
; copies of the software, And To permit persons To whom the
; software is furnished To do so, subject To the following
; conditions:
; 
; the above copyright notice And this Permission notice shall be
; included in all copies Or substantial portions of the software.
; 
; the software is PROVIDED "AS IS", without WARRANTY of any KIND,
; EXPRESS Or IMPLIED, including BUT Not LIMITED To the WARRANTIES
; of MERCHANTABILITY, FITNESS For a PARTICULAR PURPOSE And
; NONINFRINGEMENT. in NO event shall the AUTHORS Or copyright
; holders be LIABLE For any CLAIM, DAMAGES Or OTHER LIABILITY,
; WHETHER in AN ACTION of CONTRACT, TORT Or OTHERWISE, ARISING
; FROM, OUT of Or in CONNECTION With the software Or the use Or
; OTHER DEALINGS in the software.

XIncludeFile "threadMessaging.pbi"

Enumeration	
	#Message_DispatchedFunction
	
	#Message_CustomInternMAX
EndEnumeration


Prototype DispatchProc(Array Param.t_multiDatatype(1)) 

Structure t_dispatch
	*func.DispatchProc
	Array Param.t_multiDatatype(10)
EndStructure

Procedure dispatchProcedure(*func.DispatchProc, Array Param.t_multiDatatype(1))
	Protected *temp.t_dispatch = AllocateMemory(SizeOf(t_dispatch))
	InitializeStructure(*temp, t_dispatch)
	
	*temp\func = *func;
	CopyArray(Param(), *temp\Param())
	
	CreateMessage(#Message_DispatchedFunction, *temp, #PB_Function)
EndProcedure

Procedure callDispatchedProcedure(*message.t_message)
	Protected temp.t_dispatch;
	
	If *message\dataType = #PB_Function
		CopyMemory(*message\eventData, @temp, SizeOf(t_dispatch))
		temp\func(temp\Param())
	Else
		Debug "Dispatched Datatype Error!!!"
	EndIf	
EndProcedure
gadgetEventHandler.pbi

Code: Alles auswählen

; Gadget Event Handler Library

; Needs: 	threadMessaging.pbi
;			memory.pbi

; License: MIT-License
; Copyright (c) 2010 Blackskyliner
; 
; Permission is hereby granted, free of charge, To any person
; obtaining a copy of this software And associated documentation
; files (the "Software"), To deal in the software without
; restriction, including without limitation the rights To use,
; copy, modify, merge, publish, distribute, sublicense, And/or sell
; copies of the software, And To permit persons To whom the
; software is furnished To do so, subject To the following
; conditions:
; 
; the above copyright notice And this Permission notice shall be
; included in all copies Or substantial portions of the software.
; 
; the software is PROVIDED "AS IS", without WARRANTY of any KIND,
; EXPRESS Or IMPLIED, including BUT Not LIMITED To the WARRANTIES
; of MERCHANTABILITY, FITNESS For a PARTICULAR PURPOSE And
; NONINFRINGEMENT. in NO event shall the AUTHORS Or copyright
; holders be LIABLE For any CLAIM, DAMAGES Or OTHER LIABILITY,
; WHETHER in AN ACTION of CONTRACT, TORT Or OTHERWISE, ARISING
; FROM, OUT of Or in CONNECTION With the software Or the use Or
; OTHER DEALINGS in the software.

XIncludeFile "threadMessaging.pbi"
XIncludeFile "memory.pbi"

#GadgetMessage = $0F

Prototype gadgetCallbackFunc(gadgetID.l, event.l)

Structure t_gadgetElement
	gadgetID.l
	event.l
	*func.gadgetCallbackFunc
EndStructure

Procedure registerGadgetCallback(eventHandleLoop.l, gadgetID.l, event.l, *callback.gadgetCallbackFunc)
	Protected *temp.t_gadgetElement = AllocateMemory_(SizeOf(t_gadgetElement))
	
	*temp\event = event
	*temp\func = *callback
	*temp\gadgetID = gadgetID
	
	CreateMessage(eventHandleLoop, *temp, #GadgetMessage, #True, #True)
EndProcedure


Procedure unregisterGadgetCallback(eventHandleLoop.l, gadgetID.l, event.l, *callback.gadgetCallbackFunc)
	Protected temp.t_message
	Protected temp2.t_gadgetElement
	
	; Dirty... could lead to double executing...
	LockMutex(ThreadEventMessageMutex) ;>
		ResetList(ThreadEventMessageList())
		While NextElement(ThreadEventMessageList())
			ThreadEventMessageList()\wasCalled = #False	
		Wend
	UnlockMutex(ThreadEventMessageMutex) ;<
	
	; Also dity becaus use of "intern" threadMessaging functions...
	While GetMessages(@temp)
		If temp\eventCode = eventHandleLoop Or eventHandleLoop = #PB_Any
			If temp\dataType = #GadgetMessage
				CopyMemory(temp\eventData, @temp2, SizeOf(t_gadgetElement))
				If temp2\event = event Or event = #PB_Any
					If temp2\gadgetID = gadgetID Or gadgetID = #PB_Any
						If temp2\func = *callback Or *callback = #Null
							LockMutex(ThreadEventMessageMutex) ;>
								DeleteElement(ThreadEventMessageList())
							UnlockMutex(ThreadEventMessageMutex) ;<
							DeleteMessage(@temp)
						EndIf
					EndIf
				EndIf
			EndIf
		EndIf
	Wend
EndProcedure

Procedure handleGadgetCallbacks(*message.t_message)
	Protected temp.t_gadgetElement
	Protected GadgetEventID.l = EventGadget()
	CopyMemory(*message\eventData, @temp, SizeOf(t_gadgetElement))
	
	If temp\gadgetID = GadgetEventID
		If EventType() = temp\event
			temp\func(temp\gadgetID, temp\event)
		EndIf
	EndIf
EndProcedure
example.pb

Code: Alles auswählen

; Example for the usage of:
; 	- Thread Messaging Library
;	- Function Dispatcher Library
;	- Gadget Event Handler Library

; Needs: 	multiDatatype.pbi
;		threadMessaging.pbi
;		dispatcher.pbi
;		gadgetEventHandler.pbi
;		memory.pbi

; License: MIT-License
; Copyright (c) 2010 Blackskyliner
; 
; Permission is hereby granted, free of charge, To any person
; obtaining a copy of this software And associated documentation
; files (the "Software"), To deal in the software without
; restriction, including without limitation the rights To use,
; copy, modify, merge, publish, distribute, sublicense, And/or sell
; copies of the software, And To permit persons To whom the
; software is furnished To do so, subject To the following
; conditions:
; 
; the above copyright notice And this Permission notice shall be
; included in all copies Or substantial portions of the software.
; 
; the software is PROVIDED "AS IS", without WARRANTY of any KIND,
; EXPRESS Or IMPLIED, including BUT Not LIMITED To the WARRANTIES
; of MERCHANTABILITY, FITNESS For a PARTICULAR PURPOSE And
; NONINFRINGEMENT. in NO event shall the AUTHORS Or copyright
; holders be LIABLE For any CLAIM, DAMAGES Or OTHER LIABILITY,
; WHETHER in AN ACTION of CONTRACT, TORT Or OTHERWISE, ARISING
; FROM, OUT of Or in CONNECTION With the software Or the use Or
; OTHER DEALINGS in the software.

EnableExplicit

XIncludeFile "memory.pbi"
XIncludeFile "multiDatatype.pbi"
XIncludeFile "threadMessaging.pbi"
XIncludeFile "dispatcher.pbi"
XIncludeFile "gadgetEventHandler.pbi"

; Custom Messages
Enumeration #Message_CustomInternMAX
	#Message_AddElement
	#Message_DelElement
	
	#Message_CustomMAX
EndEnumeration

Enumeration
	#EventMessageLoop_MainWindow	
	#GadgetEventhandleLoop
EndEnumeration

Procedure DispatchMe(Array Param.t_multiDatatype(1))
	If Param(0)\type = #PB_Long
		;Debug Param(0)\long
	Else
		; Statt Debug, OnError Libary nutzen
		Debug "Invalid Type: Long expected!"
	EndIf
EndProcedure

Procedure ThreadedProcedure(dummy)
	Protected *eventDataBuffer;
	Protected str$
	Protected length.l
	Protected i.l, n.l
	
	; Dispatch a function to do whatever in the mainThread...
	Dim params.t_multiDatatype(10)
	createLongMessage(params(0), 1000)
	dispatchProcedure(@DispatchMe(), params())
	
	
	;Some test messages
	For i = 0 To 1
		str$ = "Das ist ein Test."
		length = Len(str$)
		
		*eventDataBuffer = AllocateMemory_((length+1)*SizeOf(str$))
		PokeS(*eventDataBuffer, str$)
		CreateMessage(#Message_AddElement, *eventDataBuffer, #PB_String)
		
		str$ = "Und noch einer, weils so schön ist :P."
		length = Len(str$)
		
		; Länge + Nullbyte * Size of one character
		*eventDataBuffer = AllocateMemory_((length+1)*SizeOf(str$))
		PokeS(*eventDataBuffer, str$)
		CreateMessage(#Message_AddElement, *eventDataBuffer, #PB_String)
		
		CreateMessage(#Message_AddElement, @"", #PB_String, #False)
	Next i
EndProcedure
 
; Proccess each message
Procedure MessageCallback(*message.t_message)
	Select *message\eventCode
		Case #Message_AddElement	
			If *message\dataType = #PB_String
				AddGadgetItem(0,-1,PeekS(*message\eventData))
			EndIf
			
		Case #Message_DispatchedFunction
			; Maybe do some stuff to stored data and then call the Proc.
			callDispatchedProcedure(*message)
		Default
			Debug "Unknown Event..."
	EndSelect
EndProcedure

CreateThread(@ThreadedProcedure(), #Null)

Procedure deleteButton_OnClick(gadgetID.l, event.l)
	RemoveGadgetItem(0, GetGadgetState(0))
	
	unregisterGadgetCallback(#GadgetEventhandleLoop, 1, #PB_EventType_LeftClick, @deleteButton_OnClick())
EndProcedure

Procedure exitButton_OnClick(gadgetID.l, event.l)
	End ; Dirty, because some dynamic data will not be freed...
EndProcedure

; Register one Callback function for the EventDispatcher
; Every registered function will get the EventMessagem
; one after another. (But only those which are for their ID)
registerMessageEventCallback(#EventMessageLoop_MainWindow,@MessageCallback())
registerMessageEventCallback(#GadgetEventhandleLoop, @handleGadgetCallbacks())

OpenWindow(0,0,0,300,200,"Test App")
ListViewGadget(0,0,0,300,175)
ButtonGadget(1, 0,175,150,25, "Delete Selected")
ButtonGadget(2, 150,175,150,25, "Exit App")


registerGadgetCallback(#GadgetEventhandleLoop, 1, #PB_EventType_LeftClick, @deleteButton_OnClick())
registerGadgetCallback(#GadgetEventhandleLoop, 2, #PB_EventType_LeftClick, @exitButton_OnClick())
Define event.l

Repeat 
	; EventDispatcher 
	MessageEvent(#EventMessageLoop_MainWindow)
	event = WaitWindowEvent(5)
	
	Select event
		Case #PB_Event_Gadget
			MessageEvent(#GadgetEventhandleLoop)
	EndSelect
Until event = #PB_Event_CloseWindow

unregisterGadgetCallback(#PB_Any, #PB_Any, #PB_Any, #Null)
unregisterMessageEventCallback(#PB_Any, #Null)

ShowAllocatedMemoryCount()

Kritik erwünscht :)

MFG
Blackskyliner
Zuletzt geändert von Blackskyliner am 10.06.2010 01:01, insgesamt 5-mal geändert.
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6999
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: YAED - Yet another Event Dispatcher

Beitrag von STARGÅTE »

Was ist das ?
Eine kleine Beschreibung in Worten wäre nicht schlecht, möchte nicht alles aus dem Code ziehen.
Danke :allright:
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
7x7
Beiträge: 591
Registriert: 14.08.2007 15:41
Computerausstattung: ganz toll
Wohnort: Lelbach

Re: YAED - Yet another Event Dispatcher

Beitrag von 7x7 »

Blackskyliner hat geschrieben:Copyright by Blackskyliner
Blackskyliner hat geschrieben:Lizenz: Keine, jeder kann es nutzen so wie er will und wo er will
Das widerspricht sich etwas...entweder/oder, da musst du dich schon entscheiden!

Du meinst wohl: "written by Blackskyliner" :D
- alles was ich hier im Forum sage/schreibe ist lediglich meine Meinung und keine Tatsachenbehauptung
- unkommentierter Quellcode = unqualifizierter Müll
Benutzeravatar
inc.
Beiträge: 348
Registriert: 27.10.2004 12:25

Re: YAED - Yet another Event Dispatcher

Beitrag von inc. »

Soviel ich weiss, hast du in Deutschland eh immer das Urheberrecht auf ein Werk und kannst dies auch nicht übertragen.
Was du aber wie im obigen Falle tun kannst, ist die Nutzungsrechte eingeschränkt oder uneingeschränkt abtreten (oder im Falle einer kommerziellen Software diese eingeschränkt gegen Bezahlung vergeben).
Lizenz: Keine, jeder kann es nutzen so wie er will und wo er will
Würde ich mir von Anfang an abgewöhnen, da du so bei Schadensersatzansprüchen anderer gelackmeiert bist.

Nutze eine offizielle Lizenz die deine Absicht der Übertragung der Nutzungsrechte gesichert wiedergibt:
http://www.opensource.org/licenses/bsd-license.php
http://www.opensource.org/licenses/mit-license.php
Hier gibts die OOP Option für PureBasic.
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Re: YAED - Yet another Event Dispatcher

Beitrag von Blackskyliner »

Hab mal den Hauptpost geupdated auf die aktuellste Version.


Hab deine zwei Beiträge entfernt
RSBasic
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: YAED - Yet another Event Dispatcher

Beitrag von Kiffi »

Blackskyliner hat geschrieben:- deleted -
Blackskyliner hat geschrieben:- deleted -
Blackskyliner hat geschrieben:sorry für den doppel/dreifach post...
kleiner Tipp: solange niemand auf Deine Postings geantwortet hat,
kannst Du diese selber mit dem "Beitrag löschen" - Button in der
unteren rechten Ecke entfernen.

Grüße ... Kiffi
Hygge
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Re: YAED - Yet another Event Dispatcher

Beitrag von Blackskyliner »

Sorry, hab ich nicht gesehen... Werds mir fürs nächste mal merken, danke für den Tipp :allright:
Alltägliches übersieht man schnell mal ;)
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: YAED - Yet another Event Dispatcher

Beitrag von Kiffi »

was mir noch fehlt, ist ein Beispiel, das die Stärken Deines
Systems besser hervorhebt. Momentan ist Dein Sample ja
eher unspektakulär.

Ich habe mal testweise die 5000 in Deiner Testmessage-
Schleife wieder einkommentiert, um zu sehen, wie sich
die GUI hierbei verhält.

Code: Alles auswählen

   ;Some test messages
   For i = 0 To 10 ;5000
      str$ = "Das ist ein Test."
      [...]
allerdings bekomme ich dann sofort einen IMA in folgender Zeile:

Code: Alles auswählen

      CreateMessage(#Message_AddElement, *eventDataBuffer, #PB_String)
Grüße ... Kiffi
Hygge
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Re: YAED - Yet another Event Dispatcher

Beitrag von Blackskyliner »

Threadsafe in den Compiler-Optionen auf on?

Bei mir klappt das mit den 5000 Einträgen...
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: YAED - Yet another Event Dispatcher

Beitrag von Kiffi »

Blackskyliner hat geschrieben:Threadsafe in den Compiler-Optionen auf on?
gnaaa! Jetzt funktioniert's <)

nix für ungut ... Kiffi
Hygge
Antworten