PopUp Menü

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Re: PopUp Menü

Beitrag von PureLust »

Darie hat geschrieben:Deswegen möchte ich, dass dann mein Programm aufgerufen wird, dass lediglich ein Popupmenü öffnet und dann ein Shortcut an ein bestimmtes Fenster gesendet wird... >_<
Ah, ok ... für sowas isses gedacht. Na dann geht's natürlich auch ganz einfach und auch ohne API:

Code: Alles auswählen

#WinMain            = 0
#Timer_PopUpTimeOut = 0

If OpenWindow(#WinMain, 10, 10, 140, 100, "PopUp", #PB_Window_Invisible) : Else : End : EndIf ;,#PB_Window_Invisible
ButtonGadget(0,10,10,120,30,"Open PopUp")

If CreatePopupMenu(0)
  MenuItem(1, "Cut")
  MenuItem(2, "Copy")
  MenuItem(3, "Paste")
EndIf

DisplayPopupMenu(0, WindowID(#WinMain))
AddWindowTimer(#WinMain,#Timer_PopUpTimeOut,50)

Repeat
	Event = WaitWindowEvent()
	
	Select Event
		Case #PB_Event_Timer
				Quit = #True
		Case #PB_Event_Menu
			Select EventMenu()     
				Case 1 : Debug "Cut"
					; tu dies
				Case 2 : Debug "Copy"
					; tu das
				Case 3 : Debug "Paste"
					; oder mach was ganz anderes
			EndSelect
			Quit = 1
	EndSelect

Until Quit = 1 Or Event = #PB_Event_CloseWindow
Es wird ganz einfach nach dem Schließen des PopUps ein TimeOut-Timer auf 50ms (wert natürlich frei änderbar) gesetzt.
Wenn also bis dahin noch kein #PB_Event_Menu eingetreten ist, wurde kein Menüeintrag angeklickt und das Programm beendet sich dann automatisch.

Grüße, PL.
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
Darie
Beiträge: 204
Registriert: 14.09.2004 21:51

Re: PopUp Menü

Beitrag von Darie »

Dankeschön natürlich auch an Edel, TS-Soft und PureLust für ihre Hilfe...
Repeat
PureBasic
ForEver
Benutzeravatar
Darie
Beiträge: 204
Registriert: 14.09.2004 21:51

Re: PopUp Menü

Beitrag von Darie »

Tut mir leid, dass ich hier nochmal deswegen poste. Ich hab festgestellt, dass mein Programm nicht immer korrekt geschlossen wird, wenn man ausserhalb des Menüs klickt. Leider weiss ich wirklich nicht, wie man das richtig macht, hab mir auch schon den Thread http://forums.purebasic.com/german/view ... 4195bd6211 angeschaut, blicke aber trotzdem nicht durch.

Hier ist mein aktueller Code, ihr müsstet dafür noch eine Textdatei erstellen und die Compileroption "temp. Executable im Quellverzeichnis erstellen" wählen.

hier die Texdatei, bitte als "default.pop" speichern

Code: Alles auswählen

Hallo={Shift}Hallo
String=Dies ist ein Teststring
Schwenken=h
Datum einfügen={F5}
Pinsel=b
Pipette=i
Undo={Alt}{Ctrl}z
---
Bamboo="C:\Program Files\Tablet\Pen\Consumer_CPL.exe"
---
>Submenu
Sub1=Ein Submenü
Sub2=Auch ein Submenü
<

Code: Alles auswählen

Global Quit=0
Global Target.l
Global NewList Commands.s()

#TPM_RETURNCMD = $100

Declare TransmitMessage(num)
Declare SendKeys(handle,window$,keys$)
Declare.s GetExeFromHandle(hWnd.l = 0)
Declare.b ProgramExists(ProgrammName.s)
Declare.s GetWindowText(hwnd)
Declare WinCallback(hWnd, uMsg, wParam, lParam) 
  

Target = GetForegroundWindow_()
If ProgramExists("PopUp") : End : EndIf


GetCursorPos_(@p.point)

If OpenWindow(0, p\x,p\y , 20, 20, "PopUp",#PB_Window_Tool);, #PB_Window_Invisible
 SetWindowLongPtr_(WindowID(0),#GWL_EXSTYLE,GetWindowLongPtr_(WindowID(0),#GWL_EXSTYLE) | #WS_EX_LAYERED)
 SetLayeredWindowAttributes_(WindowID(0), 0, 1, #LWA_ALPHA)
EndIf

;SetWindowCallback(@WinCallback())

Path$ = GetPathPart(GetExeFromHandle(WindowID(0)))
File=ReadFile(#PB_Any, Path$+"default.pop")

If File
 Repeat         
   AddElement(Commands())
   Commands() = ReadString(File)
  Until Eof(File) = 1
  CloseFile(File)               
Else
 MessageRequester("Information","Konnte Datei nicht öffnen!") : End 
EndIf

LastElement(Commands())
DeleteElement(Commands())

CreatePopupMenu(0)
ForEach Commands()
  If Commands() = "---"
   MenuBar() 
 ElseIf Mid(Commands(),1,1) = ">"
   OpenSubMenu(Mid(Commands(),2,Len(Commands())-1))
 ElseIf Mid(Commands(),1,1) = "<"
   CloseSubMenu()
 Else 
   MenuItem(ListIndex(Commands())+1, StringField(Commands(),1,"="))
  EndIf 
Next Commands()

;SetForegroundWindow_(WindowID(0))
;StickyWindow(0,1) 
AddWindowTimer(0,0,50)

Repeat
 
  Event = WaitWindowEvent()
  
  If Event = #PB_Event_Timer : Quit=1 : EndIf
  
  Command = TrackPopupMenu_(MenuID(0), #TPM_RETURNCMD, p\x, p\y, 0, WindowID(0), 0)
  If Command > 0
   TransmitMessage(Command)  
   Quit = 1  
 Else
   Quit = 1   
 EndIf
   
Until Quit = 1 Or Event = #PB_Event_CloseWindow

RemoveWindowTimer(0,0)

End

Procedure WinCallback(hWnd, uMsg, wParam, lParam) 
  
  
    
EndProcedure 

Procedure.s GetExeFromHandle(hWnd.l = 0)
  
  Protected Result.s, PID.l, handle.l, err.l
  Protected Entry.MODULEENTRY32
 
  If hWnd = 0 : hWnd = GetForegroundWindow_() : EndIf
 
  Entry\dwSize = SizeOf(MODULEENTRY32)
  GetWindowThreadProcessId_(hWnd, @PID)
  handle = CreateToolhelp32Snapshot_(#TH32CS_SNAPMODULE, PID)

  If handle
    err = Module32First_(handle, Entry)
    If err
       Result = PeekS(@Entry\szExePath)
    EndIf
    CloseHandle_(handle)
  EndIf 
 
  ProcedureReturn Result
EndProcedure

Procedure TransmitMessage(num)
  
  num - 1
  SelectElement(Commands(), num)
  pos = FindString(Commands(), "=", 1)
  If pos <> 0
    Commands() = Mid(Commands(), pos + 1, Len(Commands()))
  EndIf
  
  If Mid(Commands(),1,1) = Chr(34)
   Commands() = Mid(Commands(),2,Len(Commands())-2)
   RunProgram(Commands()) : ProcedureReturn
  EndIf
  
  SendKeys(Target,"",Commands())
 
EndProcedure

Procedure SendKeys(handle,window$,keys$)
  
If window$<>"" : handle=FindWindow_(0,window$) : EndIf ; Use window$ instead of handle.
   If IsWindow_(handle)=0 ; Does the target window actually exist?
      ProcedureReturn 0 ; Nope, so report 0 for failure to type.
   Else
   ; This block gives the target window the focus before typing.
   thread1=GetWindowThreadProcessId_(GetForegroundWindow_(),0)
   thread2=GetWindowThreadProcessId_(handle,0)
   If thread1<>thread2 : AttachThreadInput_(thread1,thread2,#True) : EndIf
      SetForegroundWindow_(handle) ; Target window now has the focus for typing.
      Delay(125) ; 1/8 second pause before typing, to prevent fast CPU problems.
      ; Now the actual typing starts.
      For r=1 To Len(keys$)
          vk$=Mid(keys$,r,1)
          If vk$="{" ; Special key found.
             s=FindString(keys$,"}",r+1)-(r+1) ; Get length of special key.
             s$=Mid(keys$,r+1,s) ; Get special key name.
             Select s$ ; Get virtual key code of special key.
                Case "ALTDOWN" : keybd_event_(#VK_MENU,0,0,0) ; Hold ALT down.
                Case "Alt" : keybd_event_(#VK_MENU,0,0,0) ; Hold ALT down. 
                Case "ALTUP" : keybd_event_(#VK_MENU,0,#KEYEVENTF_KEYUP,0) ; Release ALT.
                Case "BACKSPACE" : vk=#VK_BACK
                Case "CONTROLDOWN" : keybd_event_(#VK_CONTROL,0,0,0) ; Hold CONTROL down.
                Case "Ctrl" : keybd_event_(#VK_CONTROL,0,0,0) ; Hold CONTROL down
                Case "CONTROLUP" : keybd_event_(#VK_CONTROL,0,#KEYEVENTF_KEYUP,0) ; Release CONTROL.
                Case "DELETE" : vk=#VK_DELETE
                Case "DOWN" : vk=#VK_DOWN
                Case "END" : vk=#VK_END
                Case "ENTER" : vk=#VK_RETURN
                Case "T" : vk=#VK_T
                Case "A" : vk=#VK_A
                Case "D" : vk=#VK_D
                Case "X" : vk=#VK_X
                Case "V" : vk=#VK_V
                Case "F1" : vk=#VK_F1
                Case "F2" : vk=#VK_F2
                Case "F3" : vk=#VK_F3
                Case "F4" : vk=#VK_F4
                Case "F5" : vk=#VK_F5
                Case "F6" : vk=#VK_F6
                Case "F7" : vk=#VK_F7
                Case "F8" : vk=#VK_F8
                Case "F9" : vk=#VK_F9
                Case "F10" : vk=#VK_F10
                Case "F11" : vk=#VK_F11
                Case "F12" : vk=#VK_F12
                Case "ESCAPE" : vk=#VK_ESCAPE
                Case "HOME" : vk=#VK_HOME
                Case "INSERT" : vk=#VK_INSERT
                Case "LEFT" : vk=#VK_LEFT
                Case "PAGEDOWN" : vk=#VK_NEXT
                Case "PAGEUP" : vk=#VK_PRIOR
                Case "PRINTSCREEN" : vk=#VK_SNAPSHOT
                Case "RETURN" : vk=#VK_RETURN
                Case "RIGHT" : vk=#VK_RIGHT
                Case "SHIFTDOWN" : shifted=1 : keybd_event_(#VK_SHIFT,0,0,0) ; Hold SHIFT down.
                Case "Shift" : shifted=1 : keybd_event_(#VK_SHIFT,0,0,0) ; Hold SHIFT down.  
                Case "SHIFTUP" : shifted=0 : keybd_event_(#VK_SHIFT,0,#KEYEVENTF_KEYUP,0) ; Release SHIFT.
                Case "TAB" : vk=#VK_TAB
                Case "UP" : vk=#VK_UP
             EndSelect
             If Left(s$,3)<>"ALT" And Left(s$,7)<>"CONTROL" And Left(s$,5)<>"SHIFT"
                keybd_event_(vk,0,0,0) : keybd_event_(vk,0,#KEYEVENTF_KEYUP,0) ; Press the special key.
             EndIf
             r=r+s+1 ; Continue getting the keystrokes that follow the special key.
          Else
             vk=VkKeyScanEx_(Asc(vk$),GetKeyboardLayout_(0)) ; Normal key found.
             If vk>304 And shifted=0 : keybd_event_(#VK_SHIFT,0,0,0) : EndIf ; Due to shifted character.
             keybd_event_(vk,0,0,0) : keybd_event_(vk,0,#KEYEVENTF_KEYUP,0) ; Press the normal key.
             If vk>304 And shifted=0 : keybd_event_(#VK_SHIFT,0,#KEYEVENTF_KEYUP,0) : EndIf ; Due to shifted character.
          EndIf
      Next
      If thread1<>thread2 : AttachThreadInput_(thread1,thread2,#False) : EndIf ; Finished typing to target window!
      keybd_event_(#VK_MENU,0,#KEYEVENTF_KEYUP,0) ; Release ALT key if user forgot.
      keybd_event_(#VK_CONTROL,0,#KEYEVENTF_KEYUP,0) ; Release CONTROL key if user forgot.
      keybd_event_(#VK_SHIFT,0,#KEYEVENTF_KEYUP,0) ; Release SHIFT key if user forgot.
      ProcedureReturn 1 ; Report successful typing! :)
   EndIf
 EndProcedure
 
Procedure.b ProgramExists(ProgrammName.s)
   CreateMutex_(0, 1, ProgrammName)
   If (GetLastError_() = #ERROR_ALREADY_EXISTS)
      ProcedureReturn #True
   Else
      ProcedureReturn #False     
   EndIf
 EndProcedure
 
Procedure.s GetWindowText(hwnd)
  Protected l.l, buffer$
  l = GetWindowTextLength_(hwnd)+1
  buffer$ = Space(l)
  If GetWindowText_(hwnd, buffer$, l)
    ProcedureReturn buffer$
  EndIf
EndProcedure
Am besten kann man das Programm auf einem Notepadfenster testen. Leider schliesst sich mein Programm nicht immer zuverlässig.

Alexander
Repeat
PureBasic
ForEver
Benutzeravatar
Darie
Beiträge: 204
Registriert: 14.09.2004 21:51

Re: PopUp Menü

Beitrag von Darie »

Mmh, hat niemand eine Idee, was ich noch machen könnte? Sobald das Fenster unsichtbar ist, funktionieren eure Lösungsvorschläge nichtmehr. Es liegt wohl daran, dass der Fokus nach dem Öffnen nichtmehr auf meinem Fenster liegt. Hab schon versucht den Focus wieder neuzusetzen, klappt aber irgendwie auch nicht.


EDIT: Hat sich erledigt. Lösung gefunden...
Repeat
PureBasic
ForEver
Benutzeravatar
HeX0R
Beiträge: 3042
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Re: PopUp Menü

Beitrag von HeX0R »

Darie hat geschrieben: EDIT: Hat sich erledigt. Lösung gefunden...
Cool!
Der nächste, der diesen Thread findet und das selbe Problem hat, freut sich bestimmt über diesen Abschluss... :roll:
ist in Arbeit (bobobo) :)
Benutzeravatar
Darie
Beiträge: 204
Registriert: 14.09.2004 21:51

Re: PopUp Menü

Beitrag von Darie »

Das Problem bei der Sache war, dass mein unsichtbares Fenster öfters mal den Focus verloren hat und das "Quit"-Event dadurch nicht ausgelöst wurde. Hab anfangs versucht mit StickyWindow und ähnlichem den Focus zurückzuholen, dass reicht aber nicht aus. Wenn man den folgenden Code einfügt, erhält das Fenster aufjedenfall den Focus und das Problem ist gelöst:

Code: Alles auswählen

thread1=GetWindowThreadProcessId_(GetForegroundWindow_(),0)
thread2=GetWindowThreadProcessId_(WindowID(0),0)
If thread1<>thread2 : AttachThreadInput_(thread1,thread2,#True) : EndIf
SetForegroundWindow_(WindowID(0)) ; Target window now has the focus for typing.
Delay(125) ; 1/8 second pause before typing, to prevent fast CPU problems.
Repeat
PureBasic
ForEver
Benutzeravatar
HeX0R
Beiträge: 3042
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Re: PopUp Menü

Beitrag von HeX0R »

Ein bisschen viel Api, hätte eine Kombination von StickyWindow() und SetActiveWindow() nicht auch geholfen?
Benutzeravatar
Darie
Beiträge: 204
Registriert: 14.09.2004 21:51

Re: PopUp Menü

Beitrag von Darie »

Leider reicht das nicht aus <)
Repeat
PureBasic
ForEver
Antworten