Seite 1 von 2

Advanced: Heute: Modul(are)-Dialog(e) in PB unt. Windows 1.1

Verfasst: 17.06.2007 00:41
von ShadowTurtle
Hallo,

(fast) jeder kennt bekanntlich das kleine Beispiel aus dem PureArchive bei dem ein Dialog geöffnet wird. So bald man irgendein Button anklickt, dann verschwindet dieser wieder sofort.

Natürlich kann man in dieser ganzen Zeit im Main- bzw. Hauptfenster keine einzige Aktion ausführen. Das ist kein Bug, sondern eben das Feature eines Dialoges, welches Purebasic momentan (leider noch) nicht beherrscht.
Eventuell ist das sogar wegen der Betriebssystem-Unabhängigkeit gewollt, oder weil der Entwickler will das die Programme mit Purebasic ziemlich Flexibel in der Bedienung sein sollen (z.B. kann man im Purebasic Editor den Quellcode bearbeiten während das "Suchen"-Fenster geöffnet ist). Wie dem auch sei...

Ich habe nun eine kleine Library zusammengebastelt die jeder Fortgeschrittene schnell zusammenschustern kann. Allerdings hat sicherlich fast jeder hier mit seiner eigenen Libr. aufgegeben als das Thema Event-Handling angesagt war.
Erst recht, wenn dann auch noch weitere Dialoge aus einen Dialog heraus zu öffnen sein sollen.

Keine Angst, ich habe nicht aufgegeben. Das heißt: Diese Library unterstützt Rekursives öffnen von Dialogen mit entsprechendes Event-Handling und ermöglicht (bei richtiger Nutzung) sogar etwas Objekt-Orientiertes Programmieren wie in z.B. Delphi/Borland C++ Builder. Denn man kann für jedes Dialog einzelne Prozeduren als Pointer übergeben, welche z.B. bei einer Handlung, nach dem Erstellen oder auch beim Schließen aufgerufen werden sollen.

Man mache sich mal klar, dass man einzelne Events Kapsel kann ohne eine extra Funktion außerhalb eines Event-Aufrufs schreiben zu müssen.

Wie das nun Effektiv sein kann, kann man nun im folgenden Quellcode sehen. Weiter unten ist dann auch der Quellcode zur Library.

Sonntag, 17. Juni 2007
* In Gedanken hatte ich #AdvDlg_Proc_Update benutzt, obwohl eigentlich nur #WM_COMMAND abgefragt wird. Dieser Fehler ist behoben. #AdvDlg_Proc_Update existiert nicht mehr und heißt nun #AdvDlg_Proc_Command .
* Ab jetzt muss man immer vor den Setzen von Events und dem Erstellen eines Dialogs, die Funktion AdvDlg_Init() aufrufen. z.B.

Code: Alles auswählen

    AdvDlg_Init()
    AdvDlg_SetProc( #AdvDlg_Proc_Open, @MyDialog_C_Open() )
    AdvDlg_SetProc( #AdvDlg_Proc_Command, @MyDialog_C_Command() )
    AdvDlg_SetProc( #AdvDlg_Proc_Close, @MyDialog_C_Close() )
    AdvDlg_SetApiProc( #WM_LBUTTONDOWN, @MyDialog_ShowMessageOnClick() )
    *MyDialog_C = AdvDlg_Create( AdvDlg_GethWnd(), 0, 0, 100, 200, "Sample Dialog 3", #WS_POPUP | #WS_BORDER | #WS_SYSMENU | #DS_MODALFRAME | #WS_CAPTION | #DS_CENTER )
* Man kann nun auch WinApi Ereignisse als Events einbinden ( AdvDlg_SetApiProc ). Beispiel (erfahrene wissen es gut zu nutzen ...): AdvDlg_SetApiProc( #WM_LBUTTONDOWN, @MyDialog_ShowMessageOnClick() )

Nun zu den Quellcodes:

Code: Alles auswählen

; AdvancedDialog_Sample.pb V1.1
; by ShadowTurtle @ Sonntag, 14. Juni 2007
;XIncludeFile("AdvancedDialog.pb")

Procedure MyDialog_ShowMessageOnClick()
  MessageRequester("blob", "bla")
EndProcedure


Procedure MyDialog_C_Open()
  ButtonGadget(5,20,50,100,22,"This was it!")
  ButtonGadget(6,20,80,100,22,"Close")
EndProcedure

Procedure MyDialog_C_Command()
  GadgetID = AdvDlg_GetGadgetID()
  
  If GadgetID = 6
    AdvDlg_Close()
  EndIf
EndProcedure

Procedure MyDialog_C_Close()
EndProcedure



Procedure MyDialog_B_Open()
  ButtonGadget(3,20,50,100,22,"Open Dialog Nr. 3")
  ButtonGadget(4,20,80,100,22,"Close")
EndProcedure

Procedure MyDialog_B_Command()
  GadgetID = AdvDlg_GetGadgetID()
  
  If GadgetID = 3
    AdvDlg_Init()
    AdvDlg_SetProc( #AdvDlg_Proc_Open, @MyDialog_C_Open() )
    AdvDlg_SetProc( #AdvDlg_Proc_Command, @MyDialog_C_Command() )
    AdvDlg_SetProc( #AdvDlg_Proc_Close, @MyDialog_C_Close() )
    AdvDlg_SetApiProc( #WM_LBUTTONDOWN, @MyDialog_ShowMessageOnClick() )
    *MyDialog_C = AdvDlg_Create( AdvDlg_GethWnd(), 0, 0, 100, 200, "Sample Dialog 3", #WS_POPUP | #WS_BORDER | #WS_SYSMENU | #DS_MODALFRAME | #WS_CAPTION | #DS_CENTER )
  EndIf
  
  If GadgetID = 4
    AdvDlg_Close()
  EndIf
EndProcedure

Procedure MyDialog_B_Close()
EndProcedure



Procedure MyDialog_A_Open()
  ButtonGadget(1,20,50,100,22,"Open Dialog Nr. 2")
  ButtonGadget(2,20,80,100,22,"Close")
EndProcedure

Procedure MyDialog_A_Command()
  GadgetID = AdvDlg_GetGadgetID()
  
  If GadgetID = 1
    AdvDlg_Init()
    AdvDlg_SetProc( #AdvDlg_Proc_Open, @MyDialog_B_Open() )
    AdvDlg_SetProc( #AdvDlg_Proc_Command, @MyDialog_B_Command() )
    AdvDlg_SetProc( #AdvDlg_Proc_Close, @MyDialog_B_Close() )
    AdvDlg_SetApiProc( #WM_LBUTTONDOWN, @MyDialog_ShowMessageOnClick() )
    *MyDialog_B = AdvDlg_Create( AdvDlg_GethWnd(), 0, 0, 150, 250, "Sample Dialog 2", #WS_POPUP | #WS_BORDER | #WS_SYSMENU | #DS_MODALFRAME | #WS_CAPTION | #DS_CENTER )
  EndIf
  
  If GadgetID = 2
    AdvDlg_Close()
  EndIf
EndProcedure

Procedure MyDialog_A_Close()
EndProcedure

OpenWindow(0, 325, 185, 600, 330, "Main Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget | #PB_Window_TitleBar )  
AdvDlg_Init()
AdvDlg_SetProc( #AdvDlg_Proc_Open, @MyDialog_A_Open() )
AdvDlg_SetProc( #AdvDlg_Proc_Command, @MyDialog_A_Command() )
AdvDlg_SetProc( #AdvDlg_Proc_Close, @MyDialog_A_Close() )
AdvDlg_SetApiProc( #WM_LBUTTONDOWN, @MyDialog_ShowMessageOnClick() )
*MyDialog_A = AdvDlg_Create(WindowID(0), 0, 0, 200, 300, "Sample Dialog 1", #WS_POPUP | #WS_BORDER | #WS_SYSMENU | #DS_MODALFRAME | #WS_CAPTION | #DS_CENTER )

  Repeat
    Event = WaitWindowEvent()
    WindowID = EventWindow()
    GadgetID = EventGadget()
    EventType = EventType()
    
    If Event = #PB_Event_Gadget
      Debug GadgetID
    EndIf
  Until Event = #PB_Event_CloseWindow
 
End

Code: Alles auswählen

; AdvancedDialog.pb V1.1
; by ShadowTurtle @ Sonntag, 14. Juni 2007
Structure AdvDialog
  *Template.AdvDlg_Template
  *Proc
  ParWinID.l
  Title.s
  
  hWnd.l
  uMsg.l
  wParam.l
  lParam.l
EndStructure

Structure AdvDlg_Template
  style.l
  dwExtendedStyle.l
  cdit.w
  x.w
  y.w
  cx.w
  cy.w
  menu.w
  class.w
  title.l
EndStructure

Structure AdvDlg_DataStore
  *AdvDlg.AdvDialog
  *AdvDlgProcs[11]
  *AdvDlgApiProc.AdvDlg_ApiProc
EndStructure

Structure AdvDlg_ApiProc
  ApiMsg.l
  *Proc
  *NextProc.AdvDlg_ApiProc
EndStructure

Global *AdvDlg.AdvDialog
Dim *AdvDlgProcs(11)

Global *AdvDlgApiProc.AdvDlg_ApiProc
*AdvDlgApiProc = 0

Declare AdvDlg_AddDatas__()
Declare AdvDlg_SetBackDatas__()
Dim *AdvDlg_DialogsList(11)
Global AdvDlg_DialogsInList
AdvDlg_DialogsInList = 0

#AdvDlg_Proc_Open = 0
#AdvDlg_Proc_Command = 1
#AdvDlg_Proc_Close = 2

Procedure AdvDlg_Proc( hWnd, uMsg, wParam, lParam )
  Shared *AdvDlg.AdvDialog
  Shared *AdvDlgProcs()

  Select uMsg
    Case #WM_INITDIALOG
      *AdvDlg\uMsg = uMsg
      *AdvDlg\wParam = wParam
      *AdvDlg\lParam = lParam
      
      CreateGadgetList(hWnd)
      SetWindowText_(hWnd, *AdvDlg\Title )
     
      *AdvDlg\hWnd = hWnd
      
      If Not *AdvDlgProcs(0) = 0
        *RunProc = *AdvDlgProcs(0)
        CallFunctionFast(*RunProc)
      EndIf
    Case #WM_COMMAND
      *AdvDlg\uMsg = uMsg
      *AdvDlg\wParam = wParam
      *AdvDlg\lParam = lParam
      
      If Not *AdvDlgProcs(1) = 0
        *RunProc = *AdvDlgProcs(1)
        CallFunctionFast(*RunProc)
      EndIf
    Case #WM_CLOSE
      *AdvDlg\uMsg = uMsg
      *AdvDlg\wParam = wParam
      *AdvDlg\lParam = lParam

      If Not *AdvDlgProcs(2) = 0
        *RunProc = *AdvDlgProcs(2)
        CallFunctionFast(*RunProc)
      EndIf
      EndDialog_(hWnd,wParam&$FFFF)
    Default:
      *ApiPrc.AdvDlg_ApiProc = *AdvDlgApiProc
      While Not *ApiPrc = 0
        If *ApiPrc\ApiMsg.l = uMsg
          CallFunctionFast(*ApiPrc\Proc)
        EndIf
        *ApiPrc = *ApiPrc\NextProc
      Wend
  EndSelect
  
  ProcedureReturn 0
EndProcedure

Procedure AdvDlg_Init()
  *AdvDlgApiProc = 0
EndProcedure

Procedure.l AdvDlg_Create(ParentWinID, px.w, py.w, sx.w, sy.w, Title.s, style.l = -1)
  If style.l = -1
    style.l = #WS_POPUP | #WS_BORDER | #WS_SYSMENU | #DS_MODALFRAME | #WS_CAPTION | #DS_CENTER
  EndIf
  
  *DlgTemp.AdvDlg_Template = AllocateMemory(SizeOf(AdvDlg_Template))
  *DlgTemp\style = style
  *DlgTemp\x = px
  *DlgTemp\y = py
  *DlgTemp\cx = sx/2
  *DlgTemp\cy = sy/2
  
  *AdvDlg.AdvDialog = AllocateMemory(SizeOf(AdvDialog))
  *AdvDlg\Title = Title
  *AdvDlg\Template = *DlgTemp
  *AdvDlg\ParWinID = ParentWinID
  *AdvDlg\Proc = *Proc

  AdvDlg_AddDatas__()
  
  Result = DialogBoxIndirectParam_(0, *DlgTemp, ParentWinID, @AdvDlg_Proc(), 0)
  
  *ApiPrc.AdvDlg_ApiProc = *AdvDlgApiProc
  While Not *ApiPrc = 0
    *NxtApiPrc = *ApiPrc\NextProc
    
    FreeMemory(*ApiPrc)
    
    *ApiPrc = *NxtApiPrc
  Wend

  
  FreeMemory(*AdvDlg\Template)
  FreeMemory(*AdvDlg)
  
  AdvDlg_SetBackDatas__()
  
  ProcedureReturn( Result )
EndProcedure

Procedure AdvDlg_SetProc(ProcID, *ProcPointer)
  Shared *AdvDlg.AdvDialog
  Shared *AdvDlgProcs()

  *AdvDlgProcs(ProcID) = *ProcPointer
EndProcedure

Procedure AdvDlg_SetApiProc(ApiMsg, *ProcPointer)
  *ApiPrc.AdvDlg_ApiProc = AllocateMemory(SizeOf(AdvDlg_ApiProc))
  *ApiPrc\ApiMsg = ApiMsg
  *ApiPrc\Proc = *ProcPointer
  *ApiPrc\NextProc = *AdvDlgApiProc
  
  *AdvDlgApiProc = *ApiPrc
EndProcedure

Procedure AdvDlg_GetGadgetID()
  Shared *AdvDlg.AdvDialog
  ProcedureReturn( *AdvDlg\wParam&$FFFF )
EndProcedure

Procedure AdvDlg_GethWnd()
  Shared *AdvDlg.AdvDialog
  ProcedureReturn( *AdvDlg\hWnd )
EndProcedure

Procedure AdvDlg_Close()
  Shared *AdvDlg.AdvDialog
  Shared *AdvDlgProcs()

  If Not *AdvDlgProcs(2) = 0
    *RunProc = *AdvDlgProcs(2)
    CallFunctionFast(*RunProc)
  EndIf
  EndDialog_(*AdvDlg\hWnd,wParam&$FFFF)
EndProcedure

Procedure AdvDlg_AddDatas__()
  Shared *AdvDlg.AdvDialog
  Shared *AdvDlgProcs()
  
  Shared AdvDlg_DialogsInList
  Shared *AdvDlg_DialogsList()
  

  *ListEntry.AdvDlg_DataStore = AllocateMemory(SizeOf(AdvDlg_DataStore))
  *ListEntry\AdvDlg = *AdvDlg
  For I = 0 To 10
    *ListEntry\AdvDlgProcs[I] = *AdvDlgProcs(I)
  Next
  
  *ListEntry\AdvDlgApiProc = *AdvDlgApiProc

  *AdvDlg_DialogsList(AdvDlg_DialogsInList) = *ListEntry
  AdvDlg_DialogsInList = AdvDlg_DialogsInList + 1
  
EndProcedure

Procedure AdvDlg_SetBackDatas__()
  Shared *AdvDlg.AdvDialog
  Shared *AdvDlgProcs()
  
  Shared AdvDlg_DialogsInList
  Shared *AdvDlg_DialogsList()

  If AdvDlg_DialogsInList > 1
    AdvDlg_DialogsInList = AdvDlg_DialogsInList - 1
    *ListEntry.AdvDlg_DataStore = *AdvDlg_DialogsList(AdvDlg_DialogsInList-1)
    
    *AdvDlg = *ListEntry\AdvDlg
    For I = 0 To 10
      *AdvDlgProcs(I) = *ListEntry\AdvDlgProcs[I]
    Next

    *AdvDlgApiProc = *ListEntry\AdvDlgApiProc
  Else
    AdvDlg_DialogsInList = 0
  EndIf
EndProcedure
bis denne.

Verfasst: 17.06.2007 01:35
von Xaby
Ganz ehrlich, mir erschließt sich der Sinn noch nicht ganz.

Wenn man einen Wizzard erstellen möchte, dann vielleicht.

Aber das kann man auch anders regeln.

Wenn man ein Optionsmenü hat und will, dass Einstellungen vorgenommen werden und danach erst bestätigt wird.
PB-Hilfe hat geschrieben: Syntax

DisableWindow(#Window, Status)
Beschreibung

Aktiviert und deaktiviert die Benutzereingaben für das angegebene Fenster '#Window'.

'Status' kann einen der folgenden Werte annehmen:
1: Das Fenster wird deaktiviert.
0: Das Fenster wird aktiviert.

Unterstützte OS

Alle
Wenn man also verhindern möchte, dass Eingaben im Hauptfenster gemacht werden können, so lange das "Einstellungs-Fenster" offen ist, dann kann man einfach das "Haupt-Fenster" auf DISABLED setzen wenn man das "Neben-Fenster" öffnet. Und wenn man das Nebenfenster wieder schließt, ändert man wieder das DISABLED.

Bei der Suche ist es meiner Meinung nach gewollt. Ich find es gut, dass das Suchenfenster neben dem Hautpfenster offen bleiben kann.
Ist im normalen Editor zum Glück auch so.

Widerspricht ja auch dem FEATURE von MULTITASKING :? :mrgreen:

Verfasst: 17.06.2007 01:47
von ts-soft
:allright:
Umsetzung sieht schon mal gut aus. Hab ja auch schön öfters mit den
Dialogtemplates rumgespielt. War aber meist zu Faul um es zu nutzen, weil
die Simulation eines Dialoges mit PB-Mitteln etwas einfacher ist.

Das mit der Metrics sieht mir aber gepfuscht aus, geteilt durch 2 ist nicht
ganz korrekt :mrgreen:
EnableExplicit mag der Code auch nicht :wink:

Danke fürs teilen
Thomas

Verfasst: 17.06.2007 04:02
von MVXA
@Xaby
Du hast wirklich eine begrenzte Fantasie. Die Tatsache, dass Dialoge
modal sein können, ist vor allem dann vorteilhaft, wenn du in einem
Prozess, wie z.B. das Übertragen von Daten über das Netzwerk,
entdeckst, dass noch Daten nachträglich vom Benutzer angegeben
werden müssen. Dabei ist aber eine unbestimmte Anzahl an Fenstern
bereits geöffnet. So kannst du dann die Aufmerksamkeit des Benutzers
direkt auf das Dialog richten.

Verfasst: 17.06.2007 09:39
von ShadowTurtle
Ich schätze mit den Metrics ist alles soweit Ok, denn die angegebene Größe wirkt sich bei einen Dialog anscheinend an jeder Seite aus. Wenn ich z.B. Breite=4 angebe, dann sind Links und Rechts im Dialog 4 Pixel frei, insgesamt also eine Breite von 8 Pixel. Geteilt durch Zwei, und schon hat man wieder 4. Selbiges gilt für die Höhe.

Hm... Wenn ich diese Technik nun auch noch für PureBasic-Fenster & GadGets umsetzen würde, dann könnte man ja Praktisch wirklich Objekt bzw. Event-Basierend arbeiten. Ich bräuchte dann nur noch den Quellcode des Visual Designers und schon könnte ich mir selbst eine art Delphi-IDE für Purebasic basteln. Ich schätze dass das aber eine heiklere Sache ist.

Ehm.. Ich komme vom Thema ab.. naja... Viel spaß noch! <)

Verfasst: 17.06.2007 11:09
von Xaby
MVXA hat geschrieben:@Xaby
Du hast wirklich eine begrenzte Fantasie
Tja, das mag stimmen. Aber ich muss dir sagen, dass ich die meisten Dialoge echt nicht ab kann. Weil sie unsinnig im Programm angewandt werden.

Zum Beispiel beim Kopieren wie du es ansprichst.
Stell dir vor, man geht einkaufen und kommt wieder und stellt fest, dass die Eingabe vor 3 Stunden hätte erfolgen sollen und das Programm hat sich einfach mit einem Dialog bedient, als sich die Fehler zu merken und dann am Ende "meinet wegen" auch einen Dialog anzuzeigen.

Übrigens zum Thema begrenzte Fantasie hab ich was im Mülleimer verfasst. Vielleicht hast da ja schon mal reingeschaut.

Vielleicht komme ich ja auch noch einmal in die Verlegenheit, und werde mich an die Dialoge erinnern :shock:

Wer weiß. Sind auf jeden Fall cool die Dialoge, wenn man welche braucht oder haben will. :allright:

Re: Advanced: Heute: Modul(are)-Dialog(e) in PB unter Window

Verfasst: 17.06.2007 11:21
von DarkDragon
ShadowTurtle hat geschrieben:Natürlich kann man in dieser ganzen Zeit im Main- bzw. Hauptfenster keine einzige Aktion ausführen. Das ist kein Bug, sondern eben das Feature eines Dialoges, welches Purebasic momentan (leider noch) nicht beherrscht.
Fachbegriff: Modulare Dialoge. Java unterstützt das auf allen Betriebssystemen, außer auf mobilen Geräten, da ists sowieso immer Modular.

Verfasst: 17.06.2007 12:37
von ShadowTurtle
Man braucht die Dialoge ja nicht unbedingt dort einzusetzen wo sie nerven könnten, Xaby ... :)

Verfasst: 17.06.2007 13:49
von ts-soft
ShadowTurtle hat geschrieben:Ich schätze mit den Metrics ist alles soweit Ok, denn die angegebene Größe wirkt sich bei einen Dialog anscheinend an jeder Seite aus. Wenn ich z.B. Breite=4 angebe, dann sind Links und Rechts im Dialog 4 Pixel frei, insgesamt also eine Breite von 8 Pixel. Geteilt durch Zwei, und schon hat man wieder 4. Selbiges gilt für die Höhe.
Die Angabe in Pixel ist falsch, Dialoge arbeiten mit Tweeps oder so nen mist :wink:
Deine Umrechnung erzeugt also nur halbwegs passende grössen :mrgreen:

Verfasst: 17.06.2007 13:52
von Programie
Entweder der Code ist so kompliziert geschrieben oder ich verstehe ihn nicht.

Ich habe das Selbe mal nachgeschrieben:

Code: Alles auswählen

Procedure Open(Window)
 If IsWindow(Window-1)
  WindowID=WindowID(Window-1)
 EndIf
 If OpenWindow(Window,100,100,500,300,"Fenster "+Str(Window),#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered,WindowID)
  If CreateGadgetList(WindowID(Window))
   ButtonGadget(Window,10,10,480,20,"Fenster "+Str(Window+1)+" öffnen")
  EndIf
 EndIf
EndProcedure

Open(#True)

Repeat
 Select WaitWindowEvent()
  Case #PB_Event_Gadget
   Gadget=EventGadget()
   Open(Gadget+1)
   DisableWindow(Gadget,#True)
  Case #PB_Event_SizeWindow
   Window=EventWindow()
   ResizeGadget(Window,10,10,WindowWidth(Window)-20,20)
  Case #PB_Event_CloseWindow
   Window=EventWindow()
    If Window>#True
     CloseWindow(Window)
     DisableWindow(Window-1,#False)
    Else
     Quit=#True
    EndIf
 EndSelect
Until Quit
PS: Ich weiß ja nicht, was der Code von ShadownTutle noch machen könnte, außer die nicht aktiven Fenster zu blockieren. :)