How to prevent JPopUpMenu disappearing when checking checkboxes in it? - swing

I want to use JCheckBoxMenuItems in a JPopupMenu. It works, but the problem is that the popup menu disappears when a checkbox item has been checked or unchecked. So if one wants to check/uncheck several items, the popup needs to be launched repeatedly, which is irritating.
Curiously, if I use just plain JCheckBox items in the menu (instead of JCheckBoxMenuItems), the behavior is just as it should be: the popup stays there and the checkboxes can be checked/unchecked. Once done, the popup can be closed just by clicking outside it.
How do I make the popup to behave like that when the items there are JCheckBoxMenuItems? I would prefer using JCheckBoxMenuItems because of their looks.

Well, found working answer from http://forums.sun.com/thread.jspa?threadID=5432911. Basically, create a custom UI:
public class StayOpenCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI {
#Override
protected void doClick(MenuSelectionManager msm) {
menuItem.doClick(0);
}
public static ComponentUI createUI(JComponent c) {
return new StayOpenCheckBoxMenuItemUI();
}
}
And set it in the JCheckBoxMenuItem:
myJCheckBoxMenuItem.setUI(new StayOpenCheckBoxMenuItemUI());
Don't know if this is the most elegant possible solution, but works perfectly.

I ran into an issue with the nice Joonas Pulakka's answer because the "UIManager lookandFeel" was ignored.
I found the nice trick below on http://tips4java.wordpress.com/2010/09/12/keeping-menus-open/
The point is to reopen immediatly the menu after it has been closed, it's invisible and keep the application look and feel and behavior.
public class StayOpenCBItem extends JCheckBoxMenuItem {
private static MenuElement[] path;
{
getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
if (getModel().isArmed() && isShowing()) {
path = MenuSelectionManager.defaultManager().getSelectedPath();
}
}
});
}
public StayOpenCBItem(String text) {
super(text);
}
#Override
public void doClick(int pressTime) {
super.doClick(pressTime);
MenuSelectionManager.defaultManager().setSelectedPath(path);
}
}

I found a much easier solution for this problem
JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem("sample");
menuItem.putClientProperty("CheckBoxMenuItem.doNotCloseOnMouseClick", Boolean.TRUE);
I found this solution while reading the code from
BasicMenuItemUI.doNotCloseOnMouseClick()

Related

Returing the String of difficulty and clearing a txtArea, when selecting a JComboBox option

I have some code which is used to change a txtArea in a program when certain buttons are clicked then an ActionListener performs an action.
reset.addActionListener(new ButtonsAction());
hint.addActionListener(new ButtonsAction());
solve.addActionListener(new ButtonsAction());
newPuzzle.addActionListener(new ButtonsAction());
public class ButtonsAction implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {//implements actionPerformed
Object button=e.getSource();
if(button.equals(hint))
{
jtxtar.setText("Hint button clicked!");
}
else if(button.equals(reset))
{
jtxtar.setText("Reset button clicked!");
}
else if(button.equals(solve))
{
jtxtar.setText("Solve button clicked!");
}
else
{
jtxtar.setText("New Puzzle button clicked!");
}
}
}
However I also have a JComboBox which when selecting one of it's three option should also clear the field, but then add a message like, "Difficulty changed to ...." .
Looking up how JComboBox works, I believe I need to use an ItemListener rather than ActionListener. Looking at the tutorials has not helped me glean much from this however. But I did find something that said I needed a whole new Listener class to implement it.
diffBox.addItemListener(new CBoxAction());
public class CBoxAction implements ItemListener{
#Override
public void itemStateChanged(ItemEvent event) {
if(event.getStateChange() == ItemEvent.SELECTED) {
diffBox.getSelectedItem();
jtxtar.setText();
}
The problem here is I am not sure what I should have it do to tell the jtxtar clear and tell the user they changed to that difficulty.
After re-looking at Oracle's JComboBox Demo, I got my answer. I add this to my else statements, appending the last statement as else if, then adding the code that sets the jtxtar to tell the use their difficulty. No need for another class as it uses the ActionListener also.
else if(button.equals(newPuzzle))
{
jtxtar.setText("New Puzzle button clicked!");
}
else {
JComboBox diffBox = (JComboBox)e.getSource();
String difficulties = (String)diffBox.getSelectedItem();
jtxtar.setText(difficulties);
}
And now when you click the ComboBox and choose a new difficulty, the jtxtar clears and says that difficulty.

Changing the the visibility of a child component after rendering started

I have a component which consists of two children component A and B. However, the visibility of showing either A or B can only be determined after the page rendering started. I tried to do this but got back the following error:
Cannot modify component hierarchy after render phase has started
So, is there any way to change the visibility of the children components in my case?
I'm not exactly sure if I understand your problem.
I assume that you have 2 containers and want to display only one of them. If that is the case you can simply extend the onConfigure() method and change the visibility the way you want it to. This method will be called once during each rendering and is therefore preferred over extending the isVisible() method (which is called multiple times during each request).
private IModel<Boolean> switchModel = Model.of(Boolean.FALSE);
#Override
protected void onInitialize() {
super.onInitialize();
WebMarkupContainer container1 = new WebMarkupContainer("container1") {
#Override
protected void onConfigure() {
super.onConfigure();
setVisible(Boolean.TRUE.equals(switchModel.getModelObject()));
}
};
add(container1);
WebMarkupContainer container2 = new WebMarkupContainer("container2") {
#Override
protected void onConfigure() {
super.onConfigure();
setVisible(Boolean.FALSE.equals(switchModel.getModelObject()));
}
};
add(container2);
}

Want to create an automation that switches between two tabs

I am new to automation and want to create an automation test which can do following:
Open one tab --- click and get some info from that tab
Switch to another tab --- click and get some info from this tab now.
Compare the infos.
We use Page Object Model to get info from one page. However the moment, I switch to another tab -- it switches the tab successfully but does not locate any element on it.
Any idea ?
Questions I would ask is,
Is the element locator correct?
Is this a unique element locator?
Is this a synchronization issue? Are you waiting enough for the page to load before finding the element?
Is this problem particular to a browser? Is it consistent across?
Also make sure you pass on the driver object from one page object to the other. Like,
public class PageOne {
public PageOne(WebDriver driver) {
//do something in constructor
}
public void someMethodInPage1() {
driver.findElement(By.id("button1")).click();
PageTwo pageTwo = new PageTwo(driver);
pageTwo.someMethodInPage2();
}
}
public class PageTwo {
private WebDriver driver;
public PageTwo(WebDriver driver) {
//do something in constructor
this.driver = driver;
}
public void someMethodInPage2() {
driver.findElement(By.id("button2")).click();
}
}

How to add a JPopupMenu to a JMenuBar?

I have an application with a popup menu. I'd like to use the popup in the usual way (i.e., it should appear when the user right-clicks anywhere in the window), but I'd also like to attach it to the main MenuBar at the top of the window. I'm not sure how to do this.
I'd thought it would as simple as calling
myJMenuBar.add(myPopupMenu)
but this doesn't work.
JMenuBar.add() wants a JMenu parameter, not a JPopupMenu.
Does anyone have any suggestions?
Instead of trying to reuse the JPopupMenu object, the best approach would be to encapsulate the actions that the menus perform, and reuse those. The popup would trigger those actions, as would the menu items.
From the Action JavaDoc:
In addition to the actionPerformed method defined by the ActionListener interface, this interface allows the application to define, in a single place:
One or more text strings that describe the function. These strings can be used, for example, to display the flyover text for a button or to set the text in a menu item.
One or more icons that depict the function. These icons can be used for the images in a menu control, or for composite entries in a more sophisticated user interface.
The enabled/disabled state of the functionality. Instead of having to separately disable the menu item and the toolbar button, the application can disable the function that implements this interface. All components which are registered as listeners for the state change then know to disable event generation for that item and to modify the display accordingly.
and
JPopupMenu, JToolBar and JMenu all provide convenience methods for creating a component and setting the Action on the corresponding component. Refer to each of these classes for more information.
I had the same issue. A right-mouse-click as well as a top menu with exactly the same (complicated) set of menu items. The 'Action' class is something to consider if you are talking about enablement choices, but it's not dealing with visibility and in my case there was also a dynamic list of entries based on a current selection that I wanted to reuse.
So I ended up implementing a 'Bridge' design pattern (I think) for the methods I actually use (add() and addSeparator()):
public static class MenuBridge
{
private JPopupMenu popupMenu;
private JMenu menu;
public MenuBridge(JPopupMenu popupMenu)
{
this.popupMenu = popupMenu;
}
public MenuBridge(JMenu menu)
{
this.menu = menu;
}
public void addSeparator()
{
if(popupMenu!=null) popupMenu.addSeparator();
else menu.addSeparator();
}
public void add(JMenuItem item)
{
if(popupMenu!=null) popupMenu.add(item);
else menu.add(item);
}
}
So then I can write a reusable method that computes the menu items and synchronize my right mouse click with the top-level menu:
public void addTaskMenuItems(DefaultMenu menu, List<MDProcTask> taskList)
{
...
menu.add()/menu.addSeparator()
...
}
addTaskMenuItems(new DefaultMenu(popupMenu),taskList);
...
taskMenu.addMenuListener( new MenuListener() {
public void menuCanceled(MenuEvent menuevent)
{
}
public void menuDeselected(MenuEvent menuevent)
{
}
public void menuSelected(MenuEvent menuevent)
{
taskMenu.removeAll();
addTaskMenuItems( new DefaultMenu(taskMenu),getSelectedTasks());
taskMenu.revalidate();
}});

Titled frame panel for GWT (using FIELDSET and LEGEND html tags)

I'm trying to create a titled border frame in GWT, which results in this:
This can be done using HTML fieldset and legend tags, such as
<fieldset>
<legend>Connection parameters</legend>
... the rest ...
</fieldset>
I want to create a custom widget in GWT that implements that. I managed to do that, but the problem is that events that happen inside the widget (button click etc) does not get fired although I have added the handler.
My implementation of the widget is as follows:
public class TitledPanel extends Widget {
private Element legend;
private Widget content = null;
public TitledPanel() {
Element fieldset = DOM.createFieldSet();
legend = DOM.createLegend();
DOM.appendChild(fieldset, legend);
setElement(fieldset);
}
public TitledPanel(String title) {
this();
setTitle(title);
}
#Override
public String getTitle() {
return DOM.getInnerHTML(legend);
}
#Override
public void setTitle(String html) {
DOM.setInnerHTML(legend, html);
}
public Widget getContent() {
return content;
}
public void setContent(Widget content) {
if (this.content != null) {
DOM.removeChild(getElement(), this.content.getElement());
}
this.content = content;
DOM.appendChild(getElement(), content.getElement());
}
}
Do I need to extend Composite, or need to manually reroute the events, or is there other ways?
I think you're looking for CaptionPanel:
A panel that wraps its contents in a border with a caption that appears in the upper left corner of the border. This is an implementation of the fieldset HTML element.
I think the problem here is that you just call DOM.appendChild - this doesn't cause the TitledPanel to adopt the Widget. The normal course of action is that you extend Composite and then call initWidget(Widget widget) - inside the hood it calls widget.setParent(this);, which in turn makes the parent adopt this widget and attach it to the browser's document. However com.google.gwt.user.client.ui.Widget.setParent(Widget) is only package-visible so you can't call it from your code (after, for example, DOM.appendChild).
I'd recommend reading Widget Best Practices / Widget Building, especially the Clean up after yourself and/or look at the source code for some GWT Widgets, to get the idea how the GWT sees custom widget creation.
And, as Robert suggested, CaptionPanel is the safer route :)