Aktuelle Zeit: 23.05.2019 21:04

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]




Ein neues Thema erstellen Auf das Thema antworten  [ 6 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Wie erstellt man eine neue Class?
BeitragVerfasst: 21.01.2019 22:47 
Offline

Registriert: 23.08.2013 14:38
Hallo,

ich habe leider immer noch nicht verstanden wie man eine neu Class erstellt um ein verhalten eines Gadgets zu überschreiben.
Ich habe ein Xcode Beispiel auf youtube gesehen und versucht das umzusetzen, aber komme nicht weiter.
https://www.youtube.com/watch?v=7MZJxPOo_xU

Kann mir mir das jemand erklären?

Code:
ImportC ""
  class_addMethod(Class.i, Selector.i, *Callback, Types.P-ASCII)
  objc_allocateClassPair(ModelClass.i, NewClassName.P-ASCII, ExtraBytes.i)
  objc_registerClassPair(NewClass.i)
  object_setClass(ObjectToModify.i, NewClass.i)
  sel_registerName(MethodName.P-ASCII)
EndImport


Global Window_0, Button_0

; Global AppDelegate.i = CocoaMessage(0, CocoaMessage(0, 0, "NSApplication sharedApplication"), "delegate")
; Global DelegateClass.i = CocoaMessage(0, AppDelegate, "class")

Procedure buttonCallback(object.i, selector.i, dummy.i)
  Debug "Callback"
 
  view = CocoaMessage(0, WindowID(Window_0), "contentView")
  layer = CocoaMessage(0, view, "layer")
  CocoaMessage(0, view, "updateLayer", #YES)
EndProcedure

Procedure OpenWindow_0(x = 0, y = 0, width = 450, height = 160)
  Window_0 = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  Button_0 = ButtonGadget(#PB_Any, 160, 50, 130, 25, "OK")
 
  buttonCell = CocoaMessage(0, GadgetID(Button_0), "cell")

  customButtonClass = objc_allocateClassPair( CocoaMessage(0, buttonCell, "class"), "MyCustomButton", 0)
  objc_registerClassPair(customButtonClass)
  object_setClass(buttonCell, customButtonClass)
  selector = sel_registerName("isHighLighted:")
  If class_addMethod(customButtonClass, selector, @buttonCallback(), "v@:@") = #True
    Debug "successful"
  EndIf
 

EndProcedure

Procedure Window_0_Events(event)
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
   Case #PB_Menu_Quit
          ProcedureReturn #False
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
        Case Button_0
         
      EndSelect
  EndSelect
  ProcedureReturn #True
EndProcedure

OpenWindow_0()

Repeat
  event = WaitWindowEvent()
Until Window_0_Events(event) = #False

End

_________________
OSX 10.13 | PB 5.46


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie erstellt man eine neue Class?
BeitragVerfasst: 22.01.2019 23:07 
Offline
Benutzeravatar

Registriert: 25.01.2005 12:19
Es geht darum ein Subclassing einer bereits vorhandenen Klasse vorzunehmen, um dann bestimmte Methodenaufrufe abfangen und manipulieren zu können. Im englischen Forum hat empty an diesem einfachen Beispiel gezeigt, wie man bei einem StringGadget das Subclassing durchführt, um das Drücken der Escape-Taste zu entdecken und darauf zu reagieren. Ich habe sein Beispiel, das auch eine ungenutzte Prozedur zum Subclassing eines Fensters enthält, weiter versucht zu vereinfachen. Zum Beispiel ist der komplette ImportC..EndImport-Block nicht mehr notwendig, da Wilbert viele wichtige API-Aufrufe in die PureBasic-Ressourcen eingepflegt hat.

Dies ist die Vorgehensweise beim Subclassing in meinem weiter vereinfachten Beispiel:
- Die Prozedur SubclassGadget() mit der Gadget-Nummer aufrufen, für die das Subclassing durchgeführt werden soll
- Die Funktion class_addMethod_() aufrufen und folgende Parameter übergeben:
1. Den Rückgabewert des Aufrufs von SubclassGadget() (die neue abgeleitete Gadget-Klasse)
2. Die Methode sel_registerName_() mit dem gewünschten Selektor übergeben, der abgefangen werden soll (Entdeckung der Escape-Taste)
3. Den Callback, der bei Auftreten der Aktion (Drücken der Escape-Taste) aufgerufen werden soll
4. Eine Zeichenkette mit Symbolen für die Parametertypen, die im Callback ankommen
Code:
EnableExplicit

Procedure SubclassGadget(GadgetID.I, NewClassName.S)
  Protected GadgetClass.I = CocoaMessage(0, GadgetID(GadgetID), "class")
  Protected NewGadgetClass.I

  NewGadgetClass = objc_allocateClassPair_(GadgetClass, NewClassName, 0)
  objc_registerClassPair_(NewGadgetClass)
  object_setClass_(GadgetID(GadgetID), NewGadgetClass)

  ProcedureReturn NewGadgetClass
EndProcedure

ProcedureC SubclassedStringGadgetEventCallback(Object.I, Selector.I, Sender.I)
  Debug "<Esc> wurde gedrückt"
EndProcedure

Define SubclassedStringGadget.I

OpenWindow(0, 270, 100, 350, 80, "Subclassed StringGadget")
StringGadget(0, 10, 10, 330, 25, "Standard StringGadget")
StringGadget(1, 10, 45, 330, 25,
  "Subclassed StringGadget (Callback bei <Esc>-Taste)")
SetActiveGadget(1)

SubclassedStringGadget = SubclassGadget(1, "SubclassedStringGadget")
class_addMethod_(SubclassedStringGadget, sel_registerName_("cancelOperation:"),
  @SubclassedStringGadgetEventCallback(), "v@:@")

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

Bitte gib immer die von Dir verwendete MacOS-Version an (Du hattest ja längere Zeit Lion verwendet) und Deine PureBasic-Version (am besten beides in Deiner Signatur). Dies ist besonders wichtig, wenn Du speziell an dem verlinkten Beispiel in dem YouTube-Video interessiert bist, da sich in dem Bereich laut den Kommentaren viel geändert hat und bei neueren MacOS-Versionen vieles einfacher geworden ist.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie erstellt man eine neue Class?
BeitragVerfasst: 23.01.2019 15:10 
Offline

Registriert: 23.08.2013 14:38
Hallo Shardik,

ich glaube das habe ich soweit verstanden. Nur woher weis ich wann ich das Gadget selber und wann die Cell des Gadgets?
Und wie finde ich eine Liste mit möglichen Methoden wie z.B. das drücken einer Bestimmten Taste? Sind das alles NSResponder oder gibt es noch mehr?

Wenn ich das nun auf das Youtube Beispiel anwenden möchte passiert nichts.
Was habe ich da missverstanden?


Mir geht's darum ein eigenen Butten mit Hilfe des CGRectMark() zu erstellen. Das ist ideal um flexibel in Größe und Design zu bleiben.
Ich bin unter OSX 10.13 und PB 5.46 und XCode 8.3.3 am arbeiten.

Code:
Global Window_0, Button_0


Procedure SubclassGadget(gadgetID, NewClassName.s)
;   Protected buttonCell.i = CocoaMessage(0, gadgetID, "cell")

  Protected GadgetClass.i = CocoaMessage(0, gadgetID, "class")
 
 
  Protected NewGadgetClass.i

  NewGadgetClass = objc_allocateClassPair_(GadgetClass, NewClassName, 0)
  objc_registerClassPair_(NewGadgetClass)
  object_setClass_(gadgetID, NewGadgetClass)

  ProcedureReturn NewGadgetClass
EndProcedure


ProcedureC subclassedGadgetEventCallback(object.i, selector.i, sender.i)
  Debug "callBack"
EndProcedure



  Window_0 = OpenWindow(#PB_Any, 0, 0, 450, 160, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  Button_0 = ButtonGadget(#PB_Any, 160, 50, 130, 25, "OK")
 
 
  Define mySubclassedGadget.i
 
  mySubclassedGadget = SubclassGadget( GadgetID(Button_0) , "mySubclassedGadget")
  class_addMethod_(mySubclassedGadget, sel_registerName_("isHighLighted:"),
                   @subclassedGadgetEventCallback(), "v@:@")




Procedure Window_0_Events(event)
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
   Case #PB_Menu_Quit
     ProcedureReturn #False
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
        Case Button_0
         
      EndSelect
  EndSelect
  ProcedureReturn #True
EndProcedure

Repeat
  event = WaitWindowEvent()
Until Window_0_Events(event) = #False

End

_________________
OSX 10.13 | PB 5.46


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie erstellt man eine neue Class?
BeitragVerfasst: 25.01.2019 00:47 
Offline
Benutzeravatar

Registriert: 25.01.2005 12:19
Wolfram hat geschrieben:
Und wie finde ich eine Liste mit möglichen Methoden wie z.B. das drücken einer Bestimmten Taste? Sind das alles NSResponder oder gibt es noch mehr?
Die Methoden der gewünschten Klasse und die Klassen aller Elternklassen ("superclass"), von denen eine Klasse abgeleitet ist, können verwendet werden. Wilbert hat im englischen Forum gezeigt, wie man die Elternklassen ermittelt. Für das ButtonGadget erhält man die Elternklassen folgendermaßen:
Code:
Procedure.S GetInheritedObjects(Object)
  Protected Result.I
  Protected MutableArray.I = CocoaMessage(0, 0, "NSMutableArray arrayWithCapacity:", 10)
 
  Repeat
    CocoaMessage(0, MutableArray, "addObject:", CocoaMessage(0, Object, "className"))
    CocoaMessage(@Object, Object, "superclass")
  Until Object = 0
 
  CocoaMessage(@Result, MutableArray, "componentsJoinedByString:$", @"  -->  ")
  CocoaMessage(@Result, Result, "UTF8String")
 
  ProcedureReturn PeekS(Result, -1, #PB_UTF8)
 EndProcedure

OpenWindow(0, 270, 100, 150, 80, "Test")
ButtonGadget(0, 10, 30, 130, 25, "Click me!")

MessageRequester("Elternklassen:",
  "ButtonGadget  -->  " + GetInheritedObjects(GadgetID(0)))

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

Wolfram hat geschrieben:
Wenn ich das nun auf das Youtube Beispiel anwenden möchte passiert nichts.
Was habe ich da missverstanden?
Folgende Schritte sind nötig:
1. Einen Layer für das ButtonGadget anfordern:
Code:
CocoaMessage(0, GadgetID(0), "setWantsLayer:", #YES)
2. Das Subclassing des ButtonGadget durchführen:
Code:
SubclassedButtonGadget = SubclassGadget(0, "SubclassedButtonGadget")
3. Abschließend muss der Callback definiert werden, der das Bild des Button im normalen und gedrückten Zustand zeichnet:
Code:
class_addMethod_(SubclassedButtonGadget, sel_registerName_("updateLayer"),
  @UpdateLayer(), "v@")
4. Als Images habe ich die Original-Images aus dem YouTube-Video von GitHub heruntergeladen. Ich habe aus button.imageset die Datei button.png und aus button_pressed.imageset die Datei button_pressed.png heruntergeladen und im gleichen Verzeichnis wie den untenstehenden Sourcecode gespeichert.

5. Ich habe in meiner IDE unter "Werkzeuge..." das plist-Tool (von Joe Baker und Wilbert) installiert und als Auslöser "Nach dem Kompilieren/Starten" eingestellt. Außerdem habe ich die beiden Grafiken aus GitHub im Sourcecode dann so eingebunden:
Code:
;@@ DisableDebugWindow
;@R button.png
;@R button_pressed.png

Beim Kompilieren des untenstehenden Sourcecodes erhalte ich dann das gleiche Ergebnis wie im YouTube-Video: die blaue Farbe des Button verdunkelt sich beim Klicken darauf.
Bild
Ich habe den Beispiel-Code erfolgreich mit MacOS 10.9.5 'Mavericks' mit PB 5.46 x86 und x64 im ASCII- und Unicode-Modus getestet.
Code:
EnableExplicit

;@@ DisableDebugWindow
;@R button.png
;@R button_pressed.png

Define SubclassedButtonGadget.I

Procedure SubclassGadget(GadgetID.I, NewClassName.S)
  Protected GadgetClass.I = CocoaMessage(0, GadgetID(GadgetID), "class")
  Protected NewGadgetClass.I

  NewGadgetClass = objc_allocateClassPair_(GadgetClass, NewClassName, 0)
  objc_registerClassPair_(NewGadgetClass)
  object_setClass_(GadgetID(GadgetID), NewGadgetClass)

  ProcedureReturn NewGadgetClass
EndProcedure

ProcedureC UpdateLayer(SubclassedButton.I, Selector.I)
  Protected ButtonImage.S = "button.png"
  Protected ButtonPressedImage.S = "button_pressed.png"
  Protected Cell.I

  Cell = CocoaMessage(0, SubclassedButton, "cell")

  If CocoaMessage(0, Cell, "isHighlighted")
    CocoaMessage(0, CocoaMessage(0, SubclassedButton, "layer"), "setContents:",
      CocoaMessage(0, 0, "NSImage imageNamed:$", @ButtonPressedImage))
  Else
    CocoaMessage(0, CocoaMessage(0, SubclassedButton, "layer"), "setContents:",
      CocoaMessage(0, 0, "NSImage imageNamed:$", @ButtonImage))
  EndIf
EndProcedure

OpenWindow(0, 270, 100, 240, 90, "Subclassed ButtonGadget")
ButtonGadget(0, 50, 30, 140, 30, "Click me!")
SetGadgetFont(0, LoadFont(0, "Apple Chancery", 18))

CocoaMessage(0, GadgetID(0), "setWantsLayer:", #YES)
SubclassedButtonGadget = SubclassGadget(0, "SubclassedButtonGadget")
class_addMethod_(SubclassedButtonGadget, sel_registerName_("updateLayer"),
  @UpdateLayer(), "v@")

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie erstellt man eine neue Class?
BeitragVerfasst: 25.01.2019 18:55 
Offline

Registriert: 23.08.2013 14:38
Hi Shardik,

vielen Dank!
Ich habe dann in den callback noch das mit dem CGRect eingebaut und nun sind, egal bei welcher Größe, die Ecken immer schön rund.
Bild

Letzte Frage:
Warum wird denn der callback immer zweimal pro klick aufgerufen?

Code:
ProcedureC UpdateLayer(SubclassedButton.I, Selector.I)
  Protected cell.i, layer.i, image.i
  Protected Rect.CGRect
 
  Debug "UpdateLayer"

  cell = CocoaMessage(0, SubclassedButton, "cell")
  layer = CocoaMessage(0, SubclassedButton, "layer", 0 )
 
  If CocoaMessage(0, cell, "isHighlighted")
    image =CocoaMessage(0, 0, "NSImage imageNamed:$", @"button_pressed.png")
    CocoaMessage(0, layer, "setContents:", image)
   
  Else
    image =CocoaMessage(0, 0, "NSImage imageNamed:$", @"button.png")
    CocoaMessage(0, layer, "setContents:", image)
   
    CocoaMessage(@Rect, layer, "contentsCenter")
    Rect\origin\x  =0.5
    Rect\origin\y =0.5
    Rect\size\width =0
    Rect\size\height =0
    CocoaMessage(0, layer, "setContentsCenter:@", @Rect)
   
  EndIf
 
EndProcedure

_________________
OSX 10.13 | PB 5.46


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie erstellt man eine neue Class?
BeitragVerfasst: 25.01.2019 21:04 
Offline
Benutzeravatar

Registriert: 24.11.2004 13:12
Wohnort: Germany
An beide... :allright:

_________________
Alles ist möglich, fragt sich nur wie...
Projekte EventDesigner v1.x / OOP-BaseClass-Modul / OPC-Helper DLL
PB v3.30 / v5.4x - OS Mac Mini OSX 10.xx / Window 10 Pro. (X64) /Window 7 Pro. (X64) / Window XP Pro. (X86) / Ubuntu 14.04
Downloads auf Webspace


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 6 Beiträge ] 

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast


Sie dürfen keine neuen Themen in diesem Forum erstellen.
Sie dürfen keine Antworten zu Themen in diesem Forum erstellen.
Sie dürfen Ihre Beiträge in diesem Forum nicht ändern.
Sie dürfen Ihre Beiträge in diesem Forum nicht löschen.

Suche nach:
Gehe zu:  

 


Powered by phpBB © 2008 phpBB Group | Deutsche Übersetzung durch phpBB.de
subSilver+ theme by Canver Software, sponsor Sanal Modifiye