tags:

views:

4924

answers:

6

Is there a non JSNI way to add a close button to the title bar area of a DialogBox?

+2  A: 

Yes there is

No there isn't - at least not without fiddling with GWT's DialogBox class itself or by recreating the DialogBox using common widgets. This is a known issue in GWT, aka issue 1405 (Star it to show your interest).

However; DialogBox doesn't give us the tools to do this so we need to extend it - Edit: this doesn't work.

If you want to make a drop-in replacement for DialogBox you can name your class DialogBox and import it instead of the one that's included in GWT. This thread on the GWT forum gives better details on how this can be done (outdated, uses listeners) Outdated, the internals of DialogBox have been changed a lot since this thread - it doesn't work.

Here's some code I hacked to get the same results (used the linked thread for guidance). This doesn't work:

MyDialogBox:

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;

public class MyDialogBox extends DialogBox {

    private class crossHandler implements ClickHandler, MouseOverHandler, MouseOutHandler
    {

     @Override
     public void onClick(ClickEvent event) {
      hide();
      Window.alert("Click!");
     }

     @Override
     public void onMouseOver(MouseOverEvent event) {
      DOM.setStyleAttribute(cross.getElement(), "font-weight", "bold");

     }

     @Override
     public void onMouseOut(MouseOutEvent event) {
      DOM.setStyleAttribute(cross.getElement(), "font-weight", "normal");

     }


    }

    Label cross = new Label("X"); // The close button
    crossHandler crosshandler = new crossHandler();
    HTML caption = new HTML(); // The caption aka title
    HorizontalPanel captionPanel = new HorizontalPanel(); // Contains caption and cross


      /**
       * Creates an empty dialog box. It should not be shown until its child widget
       * has been added using {@link #add(Widget)}.
       */
    public MyDialogBox()
    {
     this(false);
    }

  /**
   * Creates an empty dialog box specifying its "auto-hide" property. It should
   * not be shown until its child widget has been added using
   * {@link #add(Widget)}.
   * 
   * @param autoHide <code>true</code> if the dialog should be automatically
   *          hidden when the user clicks outside of it
   */
    public MyDialogBox(boolean autoHide) {
         this(autoHide, true);
       }

    /**
     * Creates an empty dialog box specifying its "auto-hide" property. It should
     * not be shown until its child widget has been added using
     * {@link #add(Widget)}.
     * 
     * @param autoHide <code>true</code> if the dialog should be automatically
     *          hidden when the user clicks outside of it
     * @param modal <code>true</code> if keyboard and mouse events for widgets not
     *          contained by the dialog should be ignored
     */
    public MyDialogBox(boolean autoHide, boolean modal)
    {
     super(autoHide, modal);

     cross.addClickHandler(crosshandler); 
     cross.addMouseOutHandler(crosshandler);
     cross.addMouseOverHandler(crosshandler);

     captionPanel.add(caption);
     captionPanel.add(cross);
     captionPanel.setStyleName("caption");

     Element td = getCellElement(0, 1);  // Get the cell element that holds the caption
     td.setInnerHTML(""); // Remove the old caption
     td.appendChild(captionPanel.getElement());



    }

    @Override
    public void setText(String text)
    {
     caption.setText(text);
    }

    public String getText()
    {
     return caption.getText();
    } 

    public void setHtml(String html)
    {
     caption.setHTML(html);
    }

    public String getHtml()
    {
     return caption.getHTML();
    }

Note: This code doesn't work. The ClickEvent isn't sent from cross but instead from MyDialogBox regardless of whether you add ClickHandlers to the cross or not, IOW the MyDialogBox is the sender/source and therefor not possible to check against cross. When cross is clicked it doesn't fire the ClickEvent for some reasons.

Edit: It appears this cannot be done without hacks unless you either write your own DialogBox (almost) from scratch or fix issue 1405. Of course there are number of existing libraries that have already solved this problem, i.e. SmartGWT and GWT-Ext, but their implementation is made mostly from scratch.

So to answer your question in one sentence: Yes there is a way, but you're not gonna like it :)

Hannson
That's the general comment I've seen around the web, although a few people say it's possible, so I'm still holding out hope.
Organiccat
If you find out why only DialogBox fires ClickEvents (not cross) you could use my method.
Hannson
+3  A: 

A more simplier solution is to use gwt-ext (http://code.google.com/p/gwt-ext/). It is free and easy to use and integrate. You can see their showcase http://www.gwt-ext.com/demo/. I think that what you want is the MessageBox or Layout Window (they are on the Windows category of the showcase).

Regards.

ukrania
They actually go the length of creating their own box, which is certainly handy. Unfortunately, this does not lend to being able to do it with GWT code and I can't use this library in my product at this time. My site is almost done and integrating a library this size in now wouldn't be the best idea for me to do.
Organiccat
But you can integrate the library and use it onle for that specific situation, the rest will be done using the standard GWT widgets.But yes, if you used GWT-ext from the beginning, you can take a lot of advantage of its cool and useful widgets.Using a library of this size to only put a cross to close a window, maybe its not the best solution.Why don't you look at their code to the widget that you want? Maybe you can use it separately...
ukrania
A: 

You can find the closeable dialogbox in google code under the project synthfuljava. It is actually called scrollable dialog box with a close X button at the caption.

The following blog explains the impediments that had to be overcome in order for thecaption X button to be able to listen to the click event to let it work:

http://h2g2java.blessedgeek.com/2009/07/gwt-useable-closeable-scrollable.html

Blessed Geek
+1  A: 

We used GWT-ext from the begining in our project. It was a bad idea. They have lots of cool widgets, but they are not GWT widgets AND they have no compatibility with GWT widgets. Once you choose GWT-Ext, everything, even the event mechanism, must be in the GWT-Ext way, not in the GWT way. This library will not be updated for the newest version of GWT, because the javascript library Ext is no more free. We are removing GWT-Ext from our project now.

It´s not possible to add a different widget int the GWT DialogBox caption, but you can extend "DecoratedPanel" (it is the DialogBox parent). Look at the DialogBox source to learn the techniques, specially how it adds the Caption object to the panel and how the window drag is implemented.

That´s what we have done here, and it works very well. We´ve made our own Caption class that extends FocusablePanel (a SimplePanel that captures all mouse events) and we added a HorizontalPanel to it, with buttons and text. We had to override onAttach() and onDetach() just by calling the super method (they are protected).

I believe I am not allowed to put our source code in here, so I just can give you these tips.

Elton
+2  A: 

Hi,

You can do it by adding a button to the center panel of the DialogBox:

Image button = new Image(""); button.addClickHandler(new ClickHandler(){ public void onClick(ClickEvent event) { registerBox.hide();
}})); button.setStyleName("TopRight");

Then position it with CSS:

.TopRight { float:right; margin-top:-22px; width:16px; height:16px; display:block; background-image: url(images/cancel_16.png); }

BimboJones
Hum, you should add it as the first element of the panel or you will have to change the css.
BimboJones
A: 

Check out the active project: http://code.google.com/p/gwt-mosaic/

Their noble goal is, as mentioned on their page:

The goal is to provide a complete widget set by keeping the API as close as possible to the GWT's standard widgets API.

Have been trapped in the GXT vortex. Not at all a fan of how they require users to use entirely different API for listeners, etc. On their part this makes sense. After all, GXT is just a port of their existing javascript libraries. But I've been looking for this MOSAIC project for too long...

Stephen