I want to achieve:
On init () both group boxes are hidden and both GRP A and GRP B radio button enabled [ACHIEVED].
I click on GRP A radio button , GRP box 1 displayed GRP B radio button grayed out. [ACHIEVED].
Uncheck GrP A radio button GRP Box 1 hides both GRP A and B radio buttons enabled [FAILING : NOT ABLE
TO UNCHECK THE SELECTED RADIO BUTTON].
Check Group Box B radio button same process happens as described above.
You are trying to 'break' the concept of radio-buttons. The "GRP A" and "GRP B" buttons (assuming they are in the same 'group') will automatically be mutually exclusive, so long as both are enabled - you have to have one of the buttons checked (even if there are 3 or more in the same group). Thus, in your case, to un-check "GRP A" you will need to check "GRP B".
Unless, of course, you override the default handling of those radio-buttons.
To override the default handling, you can provide a handler for the BN_CLICKED message from the each of the "GRP A" and "GRP B" buttons, and explicitly set the state of both buttons to unchecked and enabled in that handler. You would also put code in that handler to hide the two groups (or show one, when appropriate).
Here's an outline of possible code, assuming your parent dialog is derived from CDialog and the IDs of the two radio-buttons are IDC_GRPA and IDC_GRPB:
BEGIN_MESSAGE_MAP(MyDialog, CDialog)
ON_CONTROL(BN_CLICKED, IDC_GRPA, &MyDialog::OnClickA)
ON_CONTROL(BN_CLICKED, IDC_GRPB, &MyDialog::OnClickB)
//... other handlers and message map entries
END_MESSAGE_MAP()
// Handler for a "GRP A" button click:
void MyDialog::OnClickA()
{
UINT checked = IsDlgButtonChecked(IDC_GRPA);
if (checked == BST_CHECKED) {
GetDlgItem(IDC_GRPB)->EnableWindow(TRUE); // ENABLE other button
CheckDlgButton(IDC_GRPA, BST_UNCHECKED); // Clear this button
CheckDlgButton(IDC_GRPB, BST_UNCHECKED); // and the other one
// Now do the required stuff to HIDE the group boxes...
}
else {
CheckDlgButton(IDC_GRPA, BST_CHECKED); // Check this button
GetDlgItem(IDC_GRPB)->EnableWindow(FALSE); // DISABLE other button
// Now do the required stuff to SHOW the "GrpBox 1" controls ...
}
}
// The "OnClickB()" handler will be very similar to the above, but with the IDs 'reversed'.
Please feel free to ask for any further clarification and/or explanation.
Related
I have an NSTextField in my window and 4 menu items with key equivalents ←↑→↓.
When the text field is selected and I press an arrow key, I would expect the cursor to move in the text field but instead the corresponding menu item action is performed.
So there has to be an issue in the responder chain. To figure out what's wrong I've watched WWDC 2010 Session 145 – Key Event Handling in Cocoa Applications mentioned in this NSMenuItem KeyEquivalent space " " bug thread.
The event flow for keys (hotkeys) is shown in the session as follows:
So I checked the call stack with a menu item which has keyEquivalent = K (just any normal key) and for a menu item which has keyEquivalent = → (right arrow key)
First: K key event call stack; Second: Right arrow key event call stack
So when pressing an arrow key, the event is sent directly to mainMenu.performKeyEquivalent, but it should actually be sent to the keyWindow right?
Why is that and how can I fix this behavior so that my NSTextField receives the arrow key events before the mainMenu does?
Interesting observation about the call stack difference. Since arrow keys play the most important role in navigation they are probably handled differently from the rest of keys, like you saw in the NSMenuItem KeyEquivalent space " " bug thread. Again, it's one of those cases when AppKit takes care of everything behind the scenes to make your life easier in 99.9% situations.
You can see the actual difference in behaviour by pressing k while textfield has the focus. Unlike with arrows, the menu item's key equivalent doesn't get triggered and input goes directly into the control.
For your situation you can use NSMenuItemValidation protocol to override the default action of enabling or disabling a specific menu item. AFAIK this can go into any responder in a chain, e.g., view controller, window, or application. So, you can enable/disable your menu items in a single place when the window's first responder is a textfield or any other control that uses these events to properly operate.
extension ViewController: NSMenuItemValidation {
func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
// Filter menu item by it's assigned action, just as an exampe.
if menuItem.action != #selector(ViewController.menuActionLeftArrowKey(_:)) { return true }
Swift.print("Validating menu item:", menuItem)
// Disable the menu item if first responder is text view.
let isTextView = self.view.window?.firstResponder is NSTextView
return !isTextView
}
}
This will get invoked prior displaying the menu in order to update item state, prior invoking menu item key equivalent in order to check if action needs sending or not, and probably in other cases when AppKit needs to check the item's state – can't think of any from the top of my head.
P.S. Above the first responder check is done against NSTextView not NSTextField, here's why.
This is the solution I've chosen, which resulted from the comments from #Willeke.
I've created a subclass of NSWindow and overridden the keyDown(with:) method. Every Window in my application (currently 2) subclass this new NavigationWindow, so that you can use the arrow keys in every window.
class NavigationWindow: NSWindow {
override func keyDown(with event: NSEvent) {
if event.keyCode == 123 || event.keyCode == 126 || event.specialKey == NSEvent.SpecialKey.pageUp {
print("navigate back")
} else if event.keyCode == 124 || event.keyCode == 125 || event.specialKey == NSEvent.SpecialKey.pageDown {
print("navigate forward")
} else {
super.keyDown(with: event)
}
}
}
This implementation registers all four arrow keys plus the page up and down keys for navigation.
These are the key codes
123: right arrow
124: left arrow
125: down arrow
126: up arrow
In Eclipse E4 (Luna), using the application model to create parts, handlers, commands, handled menu items etc, (these are not created programatically). I have a toolbar. This contains a sub-Menu item called "Filter" that contains another sub-menu of two filters. The two filters are two Handled Menu Items which are set up as "Radio" Buttons.
When I select the appropriate in the UI of my running app from the selection, the Radio button switches just fine to the selected Item. However I would like this selection to update (deselecting one Radio button and selecting the appropriate radio button of the handled menu item) when my ViewPart changes through other UI selection. Currently my ViewPart updates, but the Radio buttons are on the same previous selection through the UI.
Is there a way in which I get access both Handled Menu Item's IDs and set the selection (one to false, the other to true) when the viewer is updated.
Image of design is attached below:
Hierarchy of the application model is as follows:
Thanks in advance,
Marv
You can use the model service to find menu items. Use something like:
#Inject
EModelService modelService;
#Inject
MApplication app;
List<MMenuItem> items = modelService.findElements(app, "menu item id", MMenuItem.class, Collections.emptyList(), EModelService.IN_MAIN_MENU);
Once you have the MMenuItem you can call the setSelected(boolean) method to change the selection.
To find a menu item which is in a Part menu use:
modelService.findElements(app, "menu item id", MMenuItem.class, Collections.emptyList(), EModelService.IN_PART);
(IN_PART argument instead of IN_MAIN_MENU).
You could also specify the MPart rather than the Application as the first argument to findElements which may speed up the search.
For menus as a child of a Tool Bar Item it appears that the model services cannot find these directly. However you can find the Tool Bar Item and look at the menu yourself:
List<MToolItem> items = modelService.findElements(app, "tool bar item id", MToolItem.class, Collections.emptyList(), EModelService.IN_PART);
MToolItem item = items.get(0);
MMenu menu = item.getMenu();
List<MMenuElement> children = menu.getChildren();
... search menu elements
I solved this by starting with MPart PartID and drilling down to the HandledMenuItems on which I wanted to set the Radio Button selections, then setting the selection property for each individual HandledMenuItem.
This can probably be refactored to be more concise, but I've left the code with each step to have the solution easier to read.
BTW, in every instance / combination of the EModelService methods, the list returned a size of 0. So I'm not certain if that will work for what I'm trying to achieve. The following does work, although I'm not certain it is the most efficient means.
I hope this helps others.
// Get view part
MPart viewPart = _partService.findPart("part_id");
// get list of all menu items from the Part
List<MMenu> viewPartMenu = viewPart.getMenus();
// Get list of ViewMenus from viewPartMenu there is only one View Menu so it will be index 0
MMenu viewMenu = viewPartMenu .get(0);
// Get list of MMenuElements from the viewMenu - the children in the view menu
List<MMenuElement> viewMenuElements = viewMenu.getChildren();
// This gets me to the 2 HandledMenuItems
// Upper Most HandledMenuItem Radio Button is at viewMenuElements index 0. This is cast to MHandledMenuItem
MHandledMenuItem upperHandledMenuItem = (MHandledMenuItem) viewMenuElements.get(0);
// Set Selection
upperHandledMenuItem.setSelected(false);
// Lower Most HandledMenuItem Radio Button is at viewMenuElements index 1. This is cast to MHandledMenuItem
MHandledMenuItem lowerHandledMenuItem = (MHandledMenuItem) viewMenuElements.get(1);
// Set selection
lowerHandledMenuItem.setSelected(true);
I want a Text Field to appear when a certain item is chosen from a drop-down list. I'm using a change event.
if(this.rawValue == 1){
Tolerance.presence = "visible";
}
else{
Tolerance.presence = "hidden";
}
The problem is that the Text Field presence does not change immediately when a selection is made, but only after I go back to the list box and select again (any value, not just the same one).
The new value of the dropdown only registers after the change event. This means this.rawValue points to the old value of the dropdown in a change event.
Either move your script dropdown exit event or make use of the event.newText in the if conditional in the change event.
I have two buttons "Next element" and "Previous element" and some custom widget containing CellList.
On button clicks I call to my widget's method which changeselection in CellList by calling it's SelectionModel:
selectionModel.setSelected(value, true);
When I refresh CellList's contents, the buttons work just fine, but when I select element in list by clicking on it, this behavior happens:
For example, I have elements {0, 1, 2, 3, 4, ..} on the list. I click on element 1, then press "Next element" button two times. These SelectionChangeEvent occurs:
Change selection from 1 -> 2 (on first button press)
2 -> 3 (on second press)
3 -> 1
But after step 2 if I press "Previous" it correctly go back to element 1. So element that I clicked with mouse doesn't let selection go more than 1 step around it.
I have no idea where the third event is coming from. My only guess is that manual selection event continues pending after firing, but I don't know how to check that.
Anybody knows the reason of this problem?
upd:
I found confirmation that selection by clicking event continues to hanging there somewhere in the EventBus: when I change search filters I access SelectionModel the same way as on button clicks and set selection to first element. But if there was user click on CellList before that the same thing happens: first, selection changes to 0, second, it goes back to previously selected if new selection of data contains that element.
upd (for Ümit's question):
nextButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
/* Omitting checks that there are elements on the list,
some element is selected and isn't last */
T value = dataProvider.getList().get(currentIndex() + 1);
singleSelectionModel.setSelected(value, true);
singleSelectionModel.isSelected(value);
Element rowElement = cellList.getRowElement(index);
rowElement.scrollIntoView();
}
}
upd: Found what was causing this problem: http://code.google.com/p/google-web-toolkit/issues/detail?id=6310
It seems you need to use HandlerRegistration. So multiple click event is not called.
Refer to:
GWT Handler Registratin
and
related link
I writing a MFC which has a listview control. When the user right clicks any item , I am generating a dynamic menu item with that text that is selected in listview. Everything is displaying properly, but I do not know how to add a message map to that dynamic menu item.
Any help?
void CMyListDlg::OnRclickList(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
int nIndex = m_List.GetSelectionMark();
CString pString = m_List.GetItemText(nIndex,1);
CMenu menu, * pSubMenu;
int pos=0;
menu.LoadMenu(IDR_MENU1);
pSubMenu = menu.GetSubMenu (0);
pSubMenu->DeleteMenu(0,MF_BYPOSITION);
pSubMenu->InsertMenu(pos,MF_BYPOSITION,NULL,pString);
CPoint oPoint;
GetCursorPos (& oPoint);
pSubMenu-> TrackPopupMenu (TPM_LEFTALIGN, oPoint.x, oPoint.y, this);
*pResult = 0;
}
At the moment you are inserting the menu item with ID = 0 (NULL). That way you can't figure out which command was pressed. You have to assign an ID to the item, the simplest one is to
#define WM_MYMESSAGE WM_USER + 1
then you insert it like this:
pSubMenu->InsertMenu(pos,MF_BYPOSITION,WM_MYMESSAGE,pString);
If you override OnCommand for your window, you get your ID as wParam.
To actually figure out what happened, store some additional information in another class member, like m_nLastItemClicked or ... you get the idea?!
Check the MFCIE sample, it generates a favorite menu from the user's favorite folder and navigates to the favorite url when a favorite menu item is clicked.
Just add ON_COMMAND (and ON_UPDATE_COMMAND_UI if necessary) handlers for the menu items' IDs on your class.