curly
Full Member
Posts: 161
|
Post by curly on Nov 3, 2021 8:12:10 GMT -5
Hi, back again,
I'm using cascading popupmenus for selection, and it works really successfully, except for a small issue that I really hope can be resolved.
Is it possible to select or fix where the popupmenu appears? The top left corner of a popupmenu box appears at the point where the selected item in the previous popup was, so each popup moves lower and further to the right each time?
If not possible, I can live with it, but I have tried to be clever but not succeeded.
Kind regards, and stay safe, David
|
|
|
Post by Walt Decker on Nov 3, 2021 8:25:17 GMT -5
You should be able to pop up a menu at the cursor hot spot when the right mouse button is clicked.
|
|
|
Post by Chris Iverson on Nov 3, 2021 14:56:37 GMT -5
From my understanding, that's exactly what is happening, and it's exactly what he doesn't want.
He's using items clicked in a pop-up menu to open further pop-up menus. Each one opens where the mouse cursor is, and the mouse cursor will have moved to one of the item positions, which means the menu position is moving across the screen.
I think the only way to avoid that with LB's built in popupmenu would be to use the windows API to move the mouse before opening the second popup menu. Otherwise, you'd have to use an entirely API created menu, which can get complicated.
|
|
|
Post by Walt Decker on Nov 3, 2021 15:51:14 GMT -5
Personally, I dislike popup menus. Knowing his dislike for API he could popup the first menu then use the selection to popup a listbox containing more items and use that to popup another listbox with more items ad infinitum. Combersome, but it would work.
|
|
curly
Full Member
Posts: 161
|
Post by curly on Nov 4, 2021 7:21:30 GMT -5
Hi Walt and Chris,
Chris, you got it spot on. Can I identify the mouse position when I initially click the button to call the first popup, and insert a command immediately after the label I jump to to position the mouse back to there before opening the second popup, and so on?
Walt, I don't dislike API, I just don't understand it, I'm unable to reason any logic due to my lack of knowledge. I'm more than happy to copy and paste a routine if it does what it says on the box? I love these popupmenus as I can fill a mix of 40 text and comboboxes with just 5 fingerpokes?
So, if I'm reading correctly, API stands for Application Programming Interface,and enables my JB programme to make use of an existing Microsoft Windows programme, sort of avoiding reinventing the wheel? Can you suggest somewhere to learn how to do this please?
Back to my project, I use a few cascaded popupmenus, so it would be really good if I can make each sequence stay in the same place?
Kind regards, and stay safe
David
|
|
|
Post by tsh73 on Nov 4, 2021 8:03:01 GMT -5
curly, alycesrestaurant.com/lbpe/api.htmlread on ABCs of APIs Series by Alyce Watson Guys, I tried moving mouse cursor with SetCursorPos but it always returns 0 to me (it should mean error: docs.microsoft.com/ru-ru/windows/win32/api/winuser/nf-winuser-setcursorposReturns nonzero if successful or zero otherwise. But attempt to call GetLastError basically says "OK" ) and cursor not moved (and next GetCursorPos call returns same value.) Just do right click and see. What am I doing wrong? 'trouble with SetCursorPos(x,y): even passing constants it does nothing
'nomainwin
'portions from codes at 'https://libertybasiccom.proboards.com/thread/1658/attract-attention-text-combo-box 'by BrandonParker
'Create the struct for the ScreenToClient function Struct tagPoint, x As long, _ y As long
'tagPoint.x.struct = rect.right.struct 'tagPoint.y.struct = rect.bottom.struct ' 'Convert this X & Y Point to Client coordinates ' result = ScreenToClient(Hwnd(#main))
'open "Geometric White-board" for graphics_nsb as #geo UpperLeftX=1 UpperLeftY=1 graphicbox #geo.gr, 1,1,300,300 open "Geometric White-board" for window as #geo print #geo, "trapclose [quit]" print #geo.gr, "when rightButtonUp [popupMenu]" ' print #geo.gr, "when leftButtonDown [popupMenu]" wait ' stop and wait for a menu item to be chosen
[popupMenu] print #geo.gr,"cls" print #geo.gr, "place 0 0 " print #geo.gr, "\\LB native: ";MouseX;" "; MouseY 'native LB
res = GetCursorPos() print #geo.gr, "\res1 ";res scrX=tagPoint.x.struct scrY=tagPoint.y.struct print #geo.gr, "\Screen0 ";tagPoint.x.struct ;" "; tagPoint.y.struct 'screen
res = ScreenToClient(Hwnd(#geo.gr)) 'it does work print #geo.gr, "\res2 ";res print #geo.gr, "\toClient0 ";tagPoint.x.struct ;" "; tagPoint.y.struct 'converted to clent
'back to screen tagPoint.x.struct=MouseX+50 tagPoint.y.struct=MouseY+100 res = ClientToScreen(Hwnd(#geo.gr)) 'it does work print #geo.gr, "\res2 ";res print #geo.gr, "\Screen1 ";tagPoint.x.struct ;" "; tagPoint.y.struct 'converted back to screen print #geo.gr, "\dx ";tagPoint.x.struct-scrX ;" dy "; tagPoint.y.struct-scrY
'now change screen coords 'res = SetCursorPos(scrX-30, scrY-15) 'upper line somehow fails 'scrX=scrX=30 'scrY=scrY+15 'res = SetCursorPos(scrX, scrY) '!!! DOESN'T WORK res = SetCursorPos(150, 150) 'even passing constants it does nothing print #geo.gr, "\res3 ";res ' if not(res) then call DisplayError: call DisplayError: call DisplayError res = GetCursorPos() print #geo.gr, "\res4 ";res print #geo.gr, "\ScreenAfter SetCursorPos - should change vs Screen0" print #geo.gr, "\Screen2 ";tagPoint.x.struct ;" "; tagPoint.y.struct
'print #geo, "\ ";MouseX;" "; MouseY popupmenu "&Square Spiral", [asSquare], _ "&Triangular Spiral", [asTriangle] wait
[asSquare] print #geo.gr, "cls ; home ; down ; color red" for x = 1 to 120 print #geo.gr, "go "; x; " ; turn 87" next x wait
[asTriangle] print #geo.gr, "cls ; home ; down ; color blue" for x = 1 to 120 print #geo.gr, "go "; x; " ; turn 117" next x wait
[quit] close #geo end
'--------------------- Function ScreenToClient(hWnd) CallDLL #user32, "ScreenToClient", hWnd As ulong, _ tagPoint As struct, _ ScreenToClient As long End Function
Function ClientToScreen (hWnd) CallDLL #user32, "ClientToScreen", hWnd As ulong, _ tagPoint As struct, _ ClientToScreen As long End Function
Function GetCursorPos () CallDLL #user32, "GetCursorPos", _ tagPoint As struct, _ GetCursorPos As long End Function
Function SetCursorPos ( intX, intY ) CallDLL #user32, "GetCursorPos", intX As long, _ intY As long, _ SetCursorPos As long 'really it basically says 0 - "ok" call DisplayError End Function
sub DisplayError calldll #kernel32, "GetLastError", _ ErrorCode as ulong
dwFlags = _FORMAT_MESSAGE_FROM_SYSTEM nSize = 1024 lpBuffer$ = space$(nSize); chr$(0) dwMessageID = ErrorCode
calldll #kernel32, "FormatMessageA", _ dwFlags as ulong, _ lpSource as ulong, _ dwMessageID as ulong, _ dwLanguageID as ulong, _ lpBuffer$ as ptr, _ nSize as ulong, _ Arguments as ulong, _ result as ulong
print "Error "; ErrorCode; ": "; left$(lpBuffer$, result) end sub
|
|
|
Post by Walt Decker on Nov 4, 2021 8:41:50 GMT -5
Setting the cursor at upper left of popup menu:
NOTE: Cursor is in screen coordinates:
STRUCT tRect, _ X AS LONG, _ Y AS LONG, _ X1 AS LONG, _ Y1 AS LONG
'<-------------- Get a handle ------------> PopHndl = HWND(#YourPopUpMenu)
'<------------------ Where your popup is on the screen ------------> CALLDLL #user32, "GetWindowRect", PopHndl AS ULONG, tRect AS STRUCT, RetVal AS VOID
'<------------ Set the cursor pos to upper left of popup ----------> CursPosX = tRect.X.struct + 10 CursPosY = tRect.Y.struct + 20 CALLDLL #user32, "SetCursorPos", CursPosX AS LONG, CursPosY AS LONG, RetVal AS VOID
EDIT:
When you click on a control in a window the MS system gets the screen coordinate of the cursor and converts that to the window coordinate of the control by using the User32.dll function ScreenToClient(). It then determines what kind of control was clicked and performs the appropriate action for that control.
EDIT: To put the above code in a write-once use-many function: [YOUR.POPUP.BRANCH] '<------------ SELECTION MADE HERE ---------> PopHndl = HWND(#YourPopUpHndl) RetVal = FN.NextPopUpPos(PopHndl) '<------ display you next popup or branch to next popup -----------> WAIT '<--- or goto a branch that has a wait
FUNCTION FN.NextPopUpPos(PopHndl) STRUCT tRect, _ X AS LONG, _ Y AS LONG, _ X1 AS LONG, _ Y1 AS LONG
'<------------------ Where your popup is on the screen ------------> CALLDLL #user32, "GetWindowRect", PopHndl AS ULONG, tRect AS STRUCT, RetVal AS VOID
'<------------ Set the cursor pos to upper left of popup ----------> CursPosX = tRect.X.struct + 10 CursPosY = tRect.Y.struct + 20 CALLDLL #user32, "SetCursorPos", CursPosX AS LONG, CursPosY AS LONG, RetVal AS VOID
END FUNCTION
|
|
|
Post by Walt Decker on Nov 4, 2021 9:02:44 GMT -5
SetCursorPos() must be in screen coordinates. GetCursorPos() is in screen coordinates.
STRUCT tPnt, _ X AS LONG, _ Y AS LONG
CALLDLL #user32, "GetCursorPos", tPnt AS STRUCT, RetVal AS VOID X = tPnt.X.struct + 25 Y = tPnt.Y.struct + 50 CALLDLL #user32, "SetCursorPos", X AS LONG, Y AS LONG, RetVal AS VOID
EDIT: In a graphic control LB captures the WM_MOUSEMOVE, WM_LBUTTONDOWN, and WM_RBUTTONDOWN messages. These messages contain two parameters, wParam and lParam. wParam has a code concerning the state of the CTRL and SHIFT keys and the state of the left and right mouse buttons. lParam contains the coordinate of the mouse; the low word is the horizontal position and the high word is the vertical position.
With other controls MSWIN knows where on the screen each control is and takes the appropriate action for that control.
|
|
|
Post by tsh73 on Nov 4, 2021 10:13:09 GMT -5
Thank you Walt Comparing your code with mine I found that my version of
Function SetCursorPos ( intX, intY ) actually called
CallDLL #user32, "GetCursorPos", ... %\
|
|
|
Post by tsh73 on Nov 4, 2021 12:33:32 GMT -5
|
|
curly
Full Member
Posts: 161
|
Post by curly on Nov 6, 2021 13:31:26 GMT -5
Hi Walt, You appear to have given me what I need, but being a complete novice (and really old), I'm struggling to understand what to put where? My cascaded popupmenus are something like this, and I've put your code where I think it might go?
[popup1] popupmenu "Apples", [Apples], "Pears", [Pears] 'first popupmenu PopHndl = HWND(#popup1) RetVal = FN.NextPopUpPos(PopHndl) wait [Apples] popupmenu "RedApples", [RedApples], "Green Apples", [GreenApples] PopHndl = HWND(#Apples) RetVal = FN.NextPopUpPos(PopHndl) wait [Pears} popupmenu “Red Pears”, [RedPears], “Green Pears”, [GreenPears] PopHndl = HWND(#Pears) RetVal = FN.NextPopUpPos(PopHndl) wait [RedApples] popupmenu "Large Red Apples", [LargeRedApples], "Small Red Apples", [SmallRedApples] PopHndl = HWND(#RedApples) RetVal = FN.NextPopUpPos(PopHndl) wait
etc
I have saved the Function separately, but each successive popupmenu has the top left point exactly where the mouse pointer is, so I've done something wrong?
|
|
|
Post by Walt Decker on Nov 6, 2021 15:41:17 GMT -5
David:
I am also a novice and really old also (pushing 800 really hard). I think I have lead you down the garden path. My testing of LB programmer defined popup menus indicates that they only work with graphic controls, i. e. graphicbox, graphicwindow. The reason is the only way LB can natively monitor mouse button clicks is through one of those controls. I may be wrong. Where are you getting #popup1, #Apples, #Pears, etc? Are those the names of graphic boxes? They must be the names of some control otherwise you would get an error when you ask for a handle via HWND(#popup1), etc. I can work something up based on the control but not on the popup menu window itself. Unlike regular menus, LB provides nothing with which to work.
|
|
|
Post by tsh73 on Nov 7, 2021 4:08:40 GMT -5
Try this. Just reuses position of first popup
global storedCurX, storedCurY
open "test" for graphics_nsb_nf as #gr #gr "down; trapclose [quit]" #gr "home; posxy cx cy"
'#gr "font Times_new_roman 16" txt$="Click Apples|Red Apples|Large Red Apples" 'txtW=200 #gr "stringwidth? txt$ txtW" #gr "place ";cx-txtW/2;" ";cy #gr "\";txt$
#gr, "when leftButtonDown [popup1]"
wait
[popup1] call StoreCursorPos popupmenu "Apples", [Apples], "Pears", [Pears] 'first popupmenu wait
[Apples] print "[Apples]" call RestoreCursorPos popupmenu "RedApples", [RedApples], "Green Apples", [GreenApples] wait
[Pears] print "[Pears]" call RestoreCursorPos popupmenu "Red Pears", [RedPears], "Green Pears", [GreenPears] wait
[RedApples] print " [RedApples]" call RestoreCursorPos popupmenu "Large Red Apples", [LargeRedApples], "Small Red Apples", [SmallRedApples] wait
[LargeRedApples] print " [LargeRedApples]" notice "end of chain, see mainwin" 'etc
wait
[quit] close #gr end
sub StoreCursorPos Struct tagPoint, x As long, _ y As long CallDLL #user32, "GetCursorPos", _ tagPoint As struct, _ GetCursorPos As long storedCurX = tagPoint.x.struct storedCurY = tagPoint.y.struct end sub
Sub RestoreCursorPos res = SetCursorPos(storedCurX, storedCurY) end sub
Function SetCursorPos ( intX, intY ) CallDLL #user32, "SetCursorPos", intX As long, _ intY As long, _ SetCursorPos As long End Function
|
|
|
Post by tsh73 on Nov 7, 2021 4:12:29 GMT -5
|
|
curly
Full Member
Posts: 161
|
Post by curly on Nov 7, 2021 6:18:11 GMT -5
Hi again, Walt first - thanks for your time, much appreciated - I have a regular window with a mix of 40 text and combo boxes that need to have data entered. To speed things up, I have 5 buttons, each branching to a control that prefills a group of boxes. Because of complexity of selection, when the button is clicked, control jumps to the label associated with the button, in this case [popup1], that calls a popupmenu with 5 categories. When a category is selected, control jumps to the label associated with that category, let's say [popup2], and another popupmenu presents the 5 sections in that category. With just 5 clicks, I can fill 10 or 15 of the boxes? This has proved to be really quick and efficient, but the popupmenus jump about in the window according to which items are selected from the lists. So, I put the label in the HWND(# ) statement, leaving your # inside he brackets making it HWND(#popup1). Clearly that was not the right thing to do, and as you have said, it stops the program and throws up an error. It's not a major situation for the popupmenus to move around, they work fine, but I was hoping there was a way to determine the curser position when the first popupmenu was called, and apply that to each one following on for visual effect? I hope I have explained clearly, as I said, I am a very basic novice. I think I'm quite good at planning and manipulating data, but absolute rubbish at graphicals. Anatoly, I think you are using a graphics window, and I don't think I am? my open statement reads, open "DataEntry" for window as #home, ? Will you solution work in my window? Kind regards and stay safe, David
|
|