[OOP] Methode mit BindEvent

Anfängerfragen zum Programmieren mit PureBasic.
s91
Beiträge: 20
Registriert: 07.09.2022 17:20
Wohnort: HY

[OOP] Methode mit BindEvent

Beitrag von s91 »

Hi!

Mit Hilfe von diesem Thread habe ich eine kleine Klasse gebaut, die Fensterchen und Menü erstellt:
viewtopic.php?p=344646

Die Schließfunktionalität, die sich per BindMenuEvent aus einer öffentlichen Prozedur des Moduls starten lässt, lässt sich leider nicht als Methode des Objekts einbinden. Habe ich einen Denkfehler bzw. was mache ich falsch? (siehe kommentierte Zeile am Quelltextende)

Code: Alles auswählen

declareModule  window
	
	declare new ()
	declare close_ev ()
	
	interface iWindow
		
		queryInterface (*riid, *addr)
		addRef ()
		release ()
		
		appendMenu ()
		getMenu ()
		close ()
		
	endInterface
	
	structure sWindow
		
		*vTable
		cntRef.i
		objMutex.i
		
		id.i
		menu.i
		
	endStructure
	
endDeclareModule


module  window
	
	
	procedure queryInterface (*this.sWindow, *riid, *addr)
		
		procedureReturn  $80004002
		
	endprocedure
	
	procedure addRef (*this.sWindow)
		
		lockMutex (*this\objMutex)
		
		*this\cntRef + 1
		
		unlockMutex (*this\objMutex)
		
		procedureReturn  *this\cntRef
		
	endprocedure
	
	procedure release (*this.sWindow)
		
		protected  index,  cnt
		
		with  *this
			
			lockMutex (\objMutex)
			
			if \cntRef = 0
				
				freeMutex (\objMutex)
				freeStructure (*this)
				
				procedureReturn 0
				
			else
				
				\cntRef - 1
				
			endIf
			
			unlockMutex (\objMutex)
			
			procedureReturn \cntRef
			
		endWith
		
	endprocedure
	
	
	procedure new ()
		
		protected *window.sWindow = allocateStructure (sWindow)
		
		*window\vTable = ?virtualWindow
		*window\objMutex = createMutex ()
		*window\cntRef = 0
		
		*window\id = openWindow (#pb_any, 
		                         #pb_ignore, 
		                         #pb_ignore, 
		                         640, 
		                         480, 
		                         "OOP window w/ menu", 
		                         #pb_window_systemMenu)
		
		procedureReturn *window
		
	endProcedure
	
	procedure appendMenu (*this.sWindow) ; hier wird das Menü erstellt
		
		*this\menu = createMenu (#pb_any, windowId (*this\id))
		
		menuTitle ("&File")
		menuItem  (1, "Close")
		
	endProcedure
	
	procedure getMenu (*this.sWindow)
		
		procedureReturn *this\menu
		
	endProcedure
	
	procedure close (*this.sWindow) ; eine Methode zum Selbstschließen
		
		closeWindow (*this\id)
		
	endProcedure
	
	procedure close_ev () ; eine Prozedur des Moduls, die das Programm beendet
		
		end
		
	endProcedure
	
	
	dataSection
		virtualWindow:
		data.i @queryInterface()
		data.i @addRef()
		data.i @release()
		data.i @appendMenu()
		data.i @getMenu()
		data.i @close()
	endDataSection
	
	
endModule


*window.window::iWindow = window::new ()
*window\appendMenu()

bindMenuEvent (*window\getMenu(), 1, window::@close_ev())
; bindMenuEvent (*window\getMenu(), 1, @*window\close()) ; diese Zeile will nicht !!

repeat : waitWindowEvent () : forEver
PS: sorry wem mein formStil irritiert <)
auf smartphones und tablets kann es zu kleingeschriebenen substantiven, mangelhafter zeichensetzung und schlechtem englisch kommen / i ask for apology
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: [OOP] Methode mit BindEvent

Beitrag von Mijikai »

Ich habe schon länger nichts mit Modulen gemacht aber ich denke es liegt daran, dass ein Modul vom Hauptprogramm abgekapselt ist (anderer Scope).
Das Hauptprogramm erkennt somit das Menu nicht, d.h. wenn sich BindMenuEvent() auch im Modul befindet sollte es funktionieren.
s91
Beiträge: 20
Registriert: 07.09.2022 17:20
Wohnort: HY

Re: [OOP] Methode mit BindEvent

Beitrag von s91 »

@Mijikai: Nein, das stimmt nicht. Das Menü arbeitet in PB als globales Objekt. Ich hatte im Quelltext oben Probleme mit dem @-Operator und dem *-Operator. Dies ändert aber nichts am eigentlichen Problem:

Die IDE schreibt, wenn man die Anbindung der Methode von innerhalb des Moduls versucht:

Code: Alles auswählen

The Procedure specified in '@Callback()' does not have the required argument or returntype.
Damit funktioniert also der Pointer zum Menü, als Methode hat close () aber die Struktur der Klasse zum Argument und die reicht BindMenuEvent () nicht mit. Somit muss man also einen Aufruf zur Methode bauen, der die Instanz mitliefert, welche zuvor irgendwo bei appendMenu() oder new() innerhalb des Moduls festgehalten wurde, primitivst so:

Bild

Leider müssen damit regelrecht alle Instanzen innerhalb des Moduls zusätzlich gelistet werden.

Code: Alles auswählen

declareModule  window
	
	declare new ()
	
	interface iWindow
		
		queryInterface (*riid, *addr)
		addRef ()
		release ()
		
		appendMenu ()
		getMenu ()
		close ()
		
	endInterface
	
	structure sWindow
		
		*vTable
		cntRef.i
		objMutex.i
		
		id.i
		menu.i
		
	endStructure
	
endDeclareModule


module  window
	
	global newList instances ()
	
	declare ev_close ()
	
	procedure queryInterface (*this.sWindow, *riid, *addr)
		
		procedureReturn  $80004002
		
	endprocedure
	
	procedure addRef (*this.sWindow)
		
		lockMutex (*this\objMutex)
		
		*this\cntRef + 1
		
		unlockMutex (*this\objMutex)
		
		procedureReturn  *this\cntRef
		
	endprocedure
	
	procedure release (*this.sWindow)
		
		protected  index,  cnt
		
		with  *this
			
			lockMutex (\objMutex)
			
			if \cntRef = 0
				
				freeMutex (\objMutex)
				freeStructure (*this)
				
				procedureReturn 0
				
			else
				
				\cntRef - 1
				
			endIf
			
			unlockMutex (\objMutex)
			
			procedureReturn \cntRef
			
		endWith
		
	endprocedure
	
	
	procedure new ()
		
		protected *window.sWindow = allocateStructure (sWindow)
		
		*window\vTable = ?virtualWindow
		*window\objMutex = createMutex ()
		*window\cntRef = 0
		
		*window\id = openWindow (#pb_any, 
		                         #pb_ignore, 
		                         #pb_ignore, 
		                         640, 
		                         480, 
		                         "OOP window w/ menu", 
		                         #pb_window_systemMenu)
		
		addElement (instances ())
		instances () = *window
		
		procedureReturn *window
		
	endProcedure
	
	procedure appendMenu (*this.sWindow) ; hier wird das Menü erstellt
		
		forEach instances ()
			if instances () = *this
				break
			endIf
		next
		
		*this\menu = createMenu (#pb_any, windowId (*this\id))
		
		menuTitle ("&File")
		menuItem  (1, "Close")
		
		bindMenuEvent (*this\menu, 1, @ev_close ())
		
	endProcedure
	
	procedure getMenu (*this.sWindow)
		
		procedureReturn *this\menu
		
	endProcedure
	
	procedure close (*this.sWindow) ; eine Methode zum Selbstschließen
		
		closeWindow (*this\id)
		
		end
		
	endProcedure
	
	procedure ev_close ()
		
		close (instances ())
		
	endProcedure
	
	
	dataSection
		virtualWindow:
		data.i @queryInterface()
		data.i @addRef()
		data.i @release()
		data.i @appendMenu()
		data.i @getMenu()
		data.i @close()
	endDataSection
	
	
endModule


*window.window::iWindow = window::new ()
*window\appendMenu()

repeat : waitWindowEvent () : forEver
In diesem Beispiel ist zwar BindMenuEvent innerhalb des Moduls verlegt worden, ich testete es aber auch erfolgreich von außerhalb.
auf smartphones und tablets kann es zu kleingeschriebenen substantiven, mangelhafter zeichensetzung und schlechtem englisch kommen / i ask for apology
Benutzeravatar
mk-soft
Beiträge: 3844
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: [OOP] Methode mit BindEvent

Beitrag von mk-soft »

Verwende SetWindowData um den Zeiger auf das Objekt zu hinterlegen.
Beim Menu Event holts du dir die EventWindow und danach mit GetWindowData das Objekt.

PB kümmert sich darum das die richtige EventWindow Ident kommt. Das Bei Menu und bei Gadgets

Finde auch schön das du die IUnknown richtige gefüllt hast ;)

Siehe nach 'Neu'

Code: Alles auswählen

DeclareModule  window
	
	Declare new ()
	
	Interface iWindow
		
		queryInterface (*riid, *addr)
		addRef ()
		release ()
		
		appendMenu ()
		getMenu ()
		close ()
		
	EndInterface
	
	Structure sWindow
		
		*vTable
		cntRef.i
		objMutex.i
		
		id.i
		menu.i
		
	EndStructure
	
EndDeclareModule


Module  window
	
	;Global NewList instances ()
	
	Declare ev_close ()
	
	Procedure queryInterface (*this.sWindow, *riid, *addr)
		
		ProcedureReturn  $80004002 ; #E_NOINTERFACE Lass es so damit es auch unter macOS und Linux funktioniert
		
	EndProcedure
	
	Procedure addRef (*this.sWindow)
		
		LockMutex (*this\objMutex)
		
		*this\cntRef + 1
		
		UnlockMutex (*this\objMutex)
		
		ProcedureReturn  *this\cntRef
		
	EndProcedure
	
	Procedure release (*this.sWindow)
		
		Protected  index,  cnt
		
		With  *this
			
			LockMutex (\objMutex)
			
			If \cntRef = 0
				
				FreeMutex (\objMutex)
				FreeStructure (*this)
				
				ProcedureReturn 0
				
			Else
				
				\cntRef - 1
				
			EndIf
			
			UnlockMutex (\objMutex)
			
			ProcedureReturn \cntRef
			
		EndWith
		
	EndProcedure
	
	
	Procedure new ()
		
		Protected *window.sWindow = AllocateStructure (sWindow)
		
		*window\vTable = ?virtualWindow
		*window\objMutex = CreateMutex ()
		*window\cntRef = 0
		
		*window\id = OpenWindow (#PB_Any, 
		                         #PB_Ignore, 
		                         #PB_Ignore, 
		                         640, 
		                         480, 
		                         "OOP window w/ menu", 
		                         #PB_Window_SystemMenu)
    ;- Del		
;		AddElement (instances ())
; 	instances () = *window
		
		;- Neu 
		BindEvent(#PB_Event_CloseWindow, @ev_close(), *window\id)
		
		;- Neu
		SetWindowData(*window\id, *window)
		
		ProcedureReturn *window
		
	EndProcedure
	
	Procedure appendMenu (*this.sWindow) ; hier wird das Menü erstellt
	  
	  ;- Del
; 		ForEach instances ()
; 			If instances () = *this
; 				Break
; 			EndIf
; 		Next
		
		*this\menu = CreateMenu (#PB_Any, WindowID (*this\id))
		
		MenuTitle ("&File")
		MenuItem  (1, "Close")
		
		BindMenuEvent (*this\menu, 1, @ev_close ())
		
	EndProcedure
	
	Procedure getMenu (*this.sWindow)
		
		ProcedureReturn *this\menu
		
	EndProcedure
	
	Procedure close (*this.sWindow) ; eine Methode zum Selbstschließen
		
		CloseWindow (*this\id)
		
		End
		
	EndProcedure
	
	Procedure ev_close ()
	  ;- Neu
	  Protected *this.sWindow
	  
	  *this = GetWindowData(EventWindow())
	  If *this
	    Close (*this)
	  EndIf
		
	EndProcedure
	
	
	DataSection
		virtualWindow:
		Data.i @queryInterface()
		Data.i @addRef()
		Data.i @release()
		Data.i @appendMenu()
		Data.i @getMenu()
		Data.i @close()
	EndDataSection
	
	
EndModule


*window.window::iWindow = window::new ()
*window\appendMenu()

Repeat : WaitWindowEvent () : ForEver
Ich verwendet auch SetGadgetData für Gadgets um an das Objekt zu kommen
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Antworten