如何以编程方式操作多个动态小部件上的弹出菜单
语言:Progress 10.1C
我有一个 Windows 窗体,在它上面我动态创建了许多小部件(在本例中为切换框)。我可以创建 0 到 64 个小部件,具体取决于用户当前集合中有多少个 do-hickies。当用户从一个集合更改为另一个集合时,将根据需要删除或创建小部件。表单将根据显示的小部件数量调整大小。
用户可以检查任意数量的项目,并通过从菜单栏、工具栏或键盘快捷键中选择操作来对所检查的项目执行某些处理。但我还希望用户能够右键单击单个小部件,这应该会弹出一个弹出菜单,其中包含可以仅对单击的项目执行的操作,无论是否选中。
就其本身而言,这非常简单。过去,我通过在用户单击任何一个动态控件时弹出一个弹出菜单来完成这种事情(用其他语言)。但我在进行中很难做这一简单的事情:
我无法有一个弹出菜单来响应所有小部件的右键单击。我尝试创建一个弹出菜单,然后在创建每个动态小部件时,将其弹出菜单属性设置为此菜单。问题是菜单只能应用于一个小部件。一旦我将其分配给 Widget1,我就无法将其分配给 Widget2。这导致人们想到为每个小部件创建一个单独但相同的菜单。随着小部件被销毁并重新创建,这些菜单也会被销毁和重新创建。在单个会话中,我将创建和销毁数百甚至数千个相同的菜单,而用户可能会使用其中一个菜单一两次。或者根本没有。所以这对我来说似乎不是一个好的选择。
我的下一个解决方案是创建一个可以以编程方式弹出的菜单,但所有以编程方式弹出菜单的尝试都失败了。我尝试过应用“菜单拖放”到菜单 MyMenu 和其他类似的东西,但我一生都无法弄清楚如何做到这一点。我也发现搜索这方面的信息非常困难。就好像没有人尝试过这个,而且极少数情况下有人询问过,也没有得到令人满意的答案。我怀疑这不可能完成。
在尝试所有这些事情的同时,我也遇到了鼠标菜单向下、鼠标菜单向上和鼠标菜单单击事件的无尽问题。鼠标菜单点击似乎永远不会发生,无论如何对于我的动态小部件来说不是。我不明白为什么。 MOUSE-MENU-UP 有时会发生,但这取决于 MOUSE-MENU-DOWN 和小部件以及小部件的父部件的其他事件中发生的情况。我无法确切地弄清楚它什么时候会触发或不会触发,这非常违反直觉。鼠标-菜单-向下是我唯一可以指望射击的方法。
所以:我无法以编程方式显示菜单,只能通过右键单击菜单的父级来显示它。避免拥有数百个相同菜单的唯一方法是在小部件的父级(例如默认框架)上有一个弹出菜单。
通过默认框架上的静态弹出菜单,我可以右键单击小部件,然后菜单就会出现,但如果我单击框架中的任意位置,菜单就会出现。我可以禁用菜单,然后在小部件的右键单击事件中启用它。第一次使用效果非常好;如果我单击框架中的任意位置,则不会发生任何事情(菜单被禁用),但是如果我单击我的小部件,则会启用并弹出菜单。耶!但现在菜单已启用,如果我右键单击按钮、空白区域、进度条等任意位置,就会弹出菜单。什么时候再次禁用它?菜单弹出后,用户可以单击任意位置,菜单就会消失。菜单关闭时没有触发任何事件,所以我被困住了。
抱歉,长篇大论,我将简要重申一下这个问题:我希望有一个弹出菜单,当用户右键单击多个动态创建的小部件之一时会弹出一个弹出菜单。
使用汤姆的答案,这就是我的实现方式:
/* Somewhere in Control Definitions... */
DEFINE MENU m_Popup
MENU-ITEM m_Test1 LABEL "Test 1"
MENU-ITEM m_Test2 LABEL "Test 2".
/* Somewhere, where I need to dynamically create the widgets. */
/* Loop through the items in the temp table and create a widget for each. */
FOR EACH ttItem BY ttItem.ItemName:
CREATE TOGGLE-BOX hWidget
ASSIGN
FRAME = FRAME DEFAULT-FRAME:HANDLE
LABEL = STRING(ttItem.ttItemName)
TRIGGERS:
ON MOUSE-MENU-DOWN PERSISTENT RUN GetMenu IN THIS-PROCEDURE.
END TRIGGERS.
END.
/* If the user right-clicks on any one of the widgets, this procedure */
/* is run with SELF being the widget that was clicked on. */
PROCEDURE GetMenu:
/* Remove the menu from its current owner and assign it to SELF. */
MENU m_Popup:OWNER:POPUP-MENU = ?.
SELF:POPUP-MENU = MENU m_Popup:HANDLE.
END PROCEDURE.
/* The user clicks on one of the menu items */
/* Here SELF is the menu item that was clicked. I can */
/* get m_Popup from SELF:PARENT and the widget it was */
/* was assigned to from SELF:PARENT:OWNER. */
ON CHOOSE OF MENU-ITEM m_Test1
DO:
MESSAGE "You selected " SELF:LABEL " for " SELF:PARENT:OWNER:LABEL.
END.
Language: Progress 10.1C
I have a Windows form, and on it I dynamically create a number of widgets (toggle-boxes in this case). I can create anything from 0 to 64 widgets, depending on how many do-hickies the user has in the current collection. As the user changes from one collection to another, the widgets are deleted or created as needed. The form will resize according to how many widgets are displayed.
The user can check any number of them and perform certain processes on the checked items by selecting actions from a menu bar, toolbar or keyboard shortcuts. But I also want the user to be able to right-click on a single widget, which should bring up a popup menu with actions that can be performed on just the one clicked item, whether it's checked or not.
In itself, this is pretty straight forward. In the past I had done this kind of thing (in other languages) by having a single popup menu that pops up when the user clicks on any one of the dynamic controls. But I'm having a hard time doing this simple thing in Progress:
I am unable to have one popup menu that responds to the right-click of all the widgets. I tried creating a single popup menu, and then as I create each dynamic widget, I set its popup-menu attribute to this menu. The problem is that a menu can only be applied to one widget. Once I've assigned it to Widget1, I cannot assign it to Widget2. This leads one to think of creating a seperate but identical menu for each widget. And as the widgets are destroyed and recreated, so will these menus. In a single session I will create and destroy hundreds or even thousands of these identical menus, while the user might use one of them once or twice. Or not at all. So this does not seem like a good option to me.
My next solution would be to create a single menu which I can pop up programatically, but all attempts to programatically pop up a menu have failed. I have tried APPLY "MENU-DROP" TO MENU MyMenu and other similar things and I cannot for the life of me figure out how to do it. I also find it very difficult to search for information on this. It's as if nobody else has ever tried this, and the rare cases where someone has asked about it, there has been no satisfactory answers. I'm suspecting this cannot be done.
While trying all these things, I have also had endless problems with the events MOUSE-MENU-DOWN, MOUSE-MENU-UP and MOUSE-MENU-CLICK. MOUSE-MENU-CLICK seems to never happen, not for my dynamic widgets anyway. I am unable to figure out why. MOUSE-MENU-UP occurs sometimes, but it depends on what happens in MOUSE-MENU-DOWN and other events of the widgets as well as the widgets' parents. I have not been able to figure out exactly when it will or won't fire, it's very counter-intuitive. MOUSE-MENU-DOWN is the only one I can count on firing.
So: I can't show a menu programatically, I can only show it by right clicking on the menu's parent. The only way to avoid having hundreds of identical menus, is to have a popup menu on the parent of the widgets, for example the default frame.
With a static popup menu on the default frame, I can right-click on the widgets and the menu will come up, but it comes up if I click anywhere in the frame. I can disable the menu, and then in the right-click event of the widget, I enable it. This works very well the first time; if I click anywhere in the frame, nothing happens (the menu is diabled), but if I click on my widget, the menu is enabled and pops up. Yay! But now the menu is enabled and now it pops up if I right-click anywhere, on buttons, empty space, progress bars, etc. When do I disable it again? After the menu has popped up, the user can click anywhere and the menu will dissappear. There is no event that fires when the menu is closed, so I'm stuck.
Sorry about the long ramblings, I'll restate the question briefly: I want to have one popup menu that pops up when the user right-clicks one of a number of dynamically created widgets.
Using Tom's answer, this is how I implemented it:
/* Somewhere in Control Definitions... */
DEFINE MENU m_Popup
MENU-ITEM m_Test1 LABEL "Test 1"
MENU-ITEM m_Test2 LABEL "Test 2".
/* Somewhere, where I need to dynamically create the widgets. */
/* Loop through the items in the temp table and create a widget for each. */
FOR EACH ttItem BY ttItem.ItemName:
CREATE TOGGLE-BOX hWidget
ASSIGN
FRAME = FRAME DEFAULT-FRAME:HANDLE
LABEL = STRING(ttItem.ttItemName)
TRIGGERS:
ON MOUSE-MENU-DOWN PERSISTENT RUN GetMenu IN THIS-PROCEDURE.
END TRIGGERS.
END.
/* If the user right-clicks on any one of the widgets, this procedure */
/* is run with SELF being the widget that was clicked on. */
PROCEDURE GetMenu:
/* Remove the menu from its current owner and assign it to SELF. */
MENU m_Popup:OWNER:POPUP-MENU = ?.
SELF:POPUP-MENU = MENU m_Popup:HANDLE.
END PROCEDURE.
/* The user clicks on one of the menu items */
/* Here SELF is the menu item that was clicked. I can */
/* get m_Popup from SELF:PARENT and the widget it was */
/* was assigned to from SELF:PARENT:OWNER. */
ON CHOOSE OF MENU-ITEM m_Test1
DO:
MESSAGE "You selected " SELF:LABEL " for " SELF:PARENT:OWNER:LABEL.
END.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我的好友 Mike Fechner(他目前不在 SO 上,但他做这件事比我多得多)告诉我,虽然这个例子是静态的,但非常相似的东西应该可以工作:
右键单击所有三个填充 -在你的“RUN getMenu(SELF)”中。从拥有它的人那里窃取弹出菜单。
My buddy Mike Fechner (who is not currently on SO but who does this stuff a lot more than I do) tells me that, while this example is static, something very similar should work:
ON RIGHT-MOUSE-DOWN of all three fill-in’s you "RUN getMenu (SELF)." to steal the popup menu from whomever has it.