examples - Botón Cerrar de GWT en la barra de título de DialogBox
gwt tutorial (14)
¿Hay alguna forma de no JSNI de agregar un botón de cerrar al área de la barra de título de un DialogBox?
Consulte el proyecto activo: http://code.google.com/p/gwt-mosaic/
Su noble objetivo es, como se menciona en su página:
El objetivo es proporcionar un conjunto completo de widgets manteniendo la API lo más cerca posible de la API de widgets estándar de GWT.
Han quedado atrapados en el vórtice GXT. No entiendo en absoluto cómo requieren que los usuarios usen API completamente diferente para los oyentes, etc. Por su parte, esto tiene sentido. Después de todo, GXT es solo un puerto de sus bibliotecas javascript existentes. Pero he estado buscando este proyecto MOSAIC por mucho tiempo ...
Creé esta clase de subtítulos:
public class DialogBoxCaptionWithCancel extends Composite
implements Caption, HasClickHandlers {
@UiField
HTMLPanel mainPanel;
@UiField
HTML captionLabel;
@UiField
PushButton cancelButton;
private HandlerManager handlerManager = null;
private static final Binder binder = GWT.create(Binder.class);
interface Binder extends UiBinder<Widget, DialogBoxCaptionWithCancel> {
}
public DialogBoxCaptionWithCancel() {
initWidget(binder.createAndBindUi(this));
mainPanel.setStyleName("Caption");
Image upImage = new Image("images/closeWindow.png");
Image hoverImage = new Image("images/closeWindowFocus.png");
cancelButton.getUpFace().setImage(upImage);
cancelButton.getUpHoveringFace().setImage(hoverImage);
cancelButton.setStylePrimaryName("none");
}
/*
* (non-Javadoc)
*
* @see com.google.gwt.user.client.ui.Widget#onLoad()
*/
@Override
protected void onLoad() {
super.onLoad();
handlerManager = new HandlerManager(this);
}
@UiHandler("cancelButton")
public void cancelButtonOnClick(ClickEvent event) {
handlerManager.fireEvent(event);
}
@Override
public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
return handlerManager.addHandler(MouseDownEvent.getType(), handler);
}
@Override
public HandlerRegistration addMouseUpHandler(MouseUpHandler handler) {
return handlerManager.addHandler(MouseUpEvent.getType(), handler);
}
@Override
public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
return handlerManager.addHandler(MouseOutEvent.getType(), handler);
}
@Override
public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) {
return handlerManager.addHandler(MouseOverEvent.getType(), handler);
}
@Override
public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
return handlerManager.addHandler(MouseMoveEvent.getType(), handler);
}
@Override
public HandlerRegistration addMouseWheelHandler(MouseWheelHandler handler) {
return handlerManager.addHandler(MouseWheelEvent.getType(), handler);
}
@Override
public String getHTML() {
return "";
}
@Override
public void setHTML(String html) {
}
@Override
public String getText() {
return this.captionLabel.getText();
}
@Override
public void setText(String text) {
this.captionLabel.setText(text);
}
@Override
public void setHTML(SafeHtml html) {
}
@Override
public HandlerRegistration addClickHandler(ClickHandler handler) {
return handlerManager.addHandler(ClickEvent.getType(), handler);
}
}
Las imágenes solo se capturan del comportamiento de IE8 cuando pasa el mouse sobre el botón cancelar.
Aquí está el código de UiBinder:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder
xmlns:ui=''urn:ui:com.google.gwt.uibinder''
xmlns:g=''urn:import:com.google.gwt.user.client.ui''>
<ui:style>
.htmlField {
width: 100%;
}
.pushButton {
border: none;
padding: 0px;
width: 49px;
height: 21px;
}
</ui:style>
<g:HTMLPanel ui:field="mainPanel">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td width="100%">
<g:HTML ui:field="captionLabel" addStyleNames="{style.htmlField}"></g:HTML>
</td>
<td>
<g:PushButton ui:field="cancelButton" addStyleNames="{style.pushButton}"></g:PushButton>
</td>
</tr>
</table>
</g:HTMLPanel>
</ui:UiBinder>
Entonces mi clase que amplía DialogBox tiene lo siguiente:
public class MyDialogBox extends DialogBox implements ClickHandler {
...
// instantiate the caption with the cancel button
private static DialogBoxCaptionWithCancel caption = new DialogBoxCaptionWithCancel();
...
public MyDialogBox() {
// construct the dialog box with the custom caption
super(false, false, caption);
setWidget(binder.createAndBindUi(this));
// set the caption''s text
caption.setText("My Caption");
}
....
protected void onLoad() {
super.onLoad();
// let us react to the captions cancel button
caption.addClickHandler(this);
}
...
@Override
public void onClick(ClickEvent event) {
// the caption''s cancel button was clicked
this.hide();
}
Creo que ButtonCaption de cavila es la mejor solución, pero hay un error en la implementación de la leyenda. La invocación de uno de los métodos overidden causa un bucle infinitivo porque el método se llama recursivamente.
Para evitar esto, puede llamar al método en el texto InlineLabel en su lugar:
@Override
public HandlerRegistration addMouseDownHandler( MouseDownHandler handler ) {
return text.addMouseDownHandler( handler );
}
El DIV de nivel superior del cuadro de diálogo GWT tiene un posicionamiento absoluto, por lo que puede hacer lo mismo con su botón de cierre. Esto le permite colocarlo en el cuerpo del cuadro de diálogo en lo que respecta al DOM, pero hacer que aparezca físicamente en el título.
En mi ejemplo a continuación, lo coloco en la esquina superior derecha exacta del cuadro de diálogo, y lo centro en la leyenda usando el relleno.
<ui:style>
.close {
position: absolute;
top: 0;
right: 0;
padding: 3px 3px 1px 3px !important;
border-radius: 4px;
margin: 5px;
}
</ui:style>
<g:PushButton ui:field="closeButton" addStyleNames="{style.close}">
<g:upFace image=''{closeIcon}''/>
<g:downFace image=''{closeIcon}''/>
<g:upHoveringFace image=''{closeIcon}''/>
<g:downHoveringFace image=''{closeIcon}''/>
<g:upDisabledFace image=''{closeIcon}''/>
<g:downDisabledFace image=''{closeIcon}''/>
</g:PushButton>
Esto funciona si no quieres una solución simple para la pregunta:
Image button = new Image("images/cancel.png");
button.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
hide();
}
});
button.setStyleName("dialog-close");
HorizontalPanel header = new HorizontalPanel();
header.add(new HTML("Example Tool"));
header.add(button);
setHTML(header.getElement().getInnerHTML());
Me doy cuenta de que esto es ridículamente viejo, pero puedes usar el posicionamiento absoluto con la parte superior y la derecha de 0 para obtener un widget en la esquina superior derecha. El cuadro de diálogo está en una posición absoluta, por lo que el posicionamiento de su widget va en contra de eso.
Puede encontrar el cuadro de diálogo que se puede cerrar en el código de google en el proyecto synthfuljava. En realidad se llama cuadro de diálogo desplazable con un botón Cerrar X en el título.
El siguiente blog explica los impedimentos que debieron superarse para que el botón X de captación pueda escuchar el evento click para que funcione:
http://h2g2java.blessedgeek.com/2009/07/gwt-useable-closeable-scrollable.html
Puede hacerlo agregando un botón al panel central de DialogBox:
Image closeButton = new Image("");
closeButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
registerBox.hide();
}
});
closeButton.setStyleName("TopRight");
Luego colóquelo con CSS:
.TopRight {
float:right;
margin-top:-22px;
width:16px;
height:16px;
display:block;
background-image: url(images/cancel_16.png);
}
Puedes probar esto, solución ligeramente mejorada de fungus1487:
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.HasDirection;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.*;
/**
* @author Andrey Talnikov
*/
public class ClosablePopup extends DialogBox {
private Anchor closeAnchor;
/**
* Instantiates new closable popup.
*
* @param title the title
* @param defaultClose it {@code true}, hide popup on ''x'' click
*/
public ClosablePopup(String title, boolean defaultClose) {
super(true);
closeAnchor = new Anchor("x");
FlexTable captionLayoutTable = new FlexTable();
captionLayoutTable.setWidth("100%");
captionLayoutTable.setText(0, 0, title);
captionLayoutTable.setWidget(0, 1, closeAnchor);
captionLayoutTable.getCellFormatter().setHorizontalAlignment(0, 1,
HasHorizontalAlignment.HorizontalAlignmentConstant.endOf(HasDirection.Direction.LTR));
HTML caption = (HTML) getCaption();
caption.getElement().appendChild(captionLayoutTable.getElement());
caption.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
EventTarget target = event.getNativeEvent().getEventTarget();
Element targetElement = (Element) target.cast();
if (targetElement == closeAnchor.getElement()) {
closeAnchor.fireEvent(event);
}
}
});
if (defaultClose) {
addCloseHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
hide();
}
});
}
}
public void addCloseHandler(ClickHandler handler) {
closeAnchor.addClickHandler(handler);
}
}
Simplemente usando GWT y sin bibliotecas externas, puede interceptar los eventos de clic en el elemento de título y realizar una prueba de impacto para ver si la coordinada x, y del mouse está dentro de los límites del elemento de anclaje (u otro elemento que use como ClickHandler).
// Create anchor we want to accept click events
final Anchor myAnchor = new Anchor("My Anchor");
// Add handler to anchor
myAnchor.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
Window.alert("Anchor was clicked");
}
});
// Create dialog
final DialogBox myDialog = new DialogBox();
myDialog.setText("My Dialog");
// Get caption element
final HTML caption = ((HTML)myDialog.getCaption());
// Add anchor to caption
caption.getElement().appendChild(myAnchor.getElement());
// Add click handler to caption
caption.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
// Get x,y caption click relative to the anchor
final int x = event.getRelativeX(myAnchor.getElement());
final int y = event.getRelativeY(myAnchor.getElement());
// Check click was within bounds of anchor
if(x >= 0 && y >= 0 &&
x <= myAnchor.getOffsetWidth() &&
y <= myAnchor.getOffsetHeight()) {
// Raise event on anchor
myAnchor.fireEvent(event);
}
}
});
// Show the dialog
myDialog.show();
Supongo que una respuesta simple a esto es instanciar un widget para reemplazar el widget Caption estándar de DialogBox. Creé un título que tiene un botón a la derecha y puedes elegir una referencia. Luego puede agregar cualquier evento de clic que desee.
En GWT 2.4 usé la siguiente solución:
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.dom.client.MouseWheelHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.DialogBox.Caption;
/**
* @author Cristiano Sumariva
*/
public class ButtonCaption extends HorizontalPanel implements Caption
{
protected InlineLabel text;
protected PushButton closeDialog;
/**
* @return the button at caption
*/
public PushButton getCloseButton()
{
return closeDialog;
}
public ButtonCaption( String label )
{
super();
setWidth( "100%" );
setStyleName( "Caption" ); // so you have same styling as standard caption widget
closeDialog = new PushButton();
add( text = new InlineLabel( label ) );
add( closeDialog );
setCellWidth( closeDialog, "1px" ); // to make button cell minimal enough to it
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.HasMouseDownHandlers#addMouseDownHandler(com.google.gwt.event.dom.client.MouseDownHandler)
*/
@Override
public HandlerRegistration addMouseDownHandler( MouseDownHandler handler )
{
return addMouseDownHandler( handler );
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.HasMouseUpHandlers#addMouseUpHandler(com.google.gwt.event.dom.client.MouseUpHandler)
*/
@Override
public HandlerRegistration addMouseUpHandler( MouseUpHandler handler )
{
return addMouseUpHandler( handler );
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.HasMouseOutHandlers#addMouseOutHandler(com.google.gwt.event.dom.client.MouseOutHandler)
*/
@Override
public HandlerRegistration addMouseOutHandler( MouseOutHandler handler )
{
return addMouseOutHandler( handler );
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.HasMouseOverHandlers#addMouseOverHandler(com.google.gwt.event.dom.client.MouseOverHandler)
*/
@Override
public HandlerRegistration addMouseOverHandler( MouseOverHandler handler )
{
return addMouseOverHandler( handler );
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.HasMouseMoveHandlers#addMouseMoveHandler(com.google.gwt.event.dom.client.MouseMoveHandler)
*/
@Override
public HandlerRegistration addMouseMoveHandler( MouseMoveHandler handler )
{
return addMouseMoveHandler( handler );
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.HasMouseWheelHandlers#addMouseWheelHandler(com.google.gwt.event.dom.client.MouseWheelHandler)
*/
@Override
public HandlerRegistration addMouseWheelHandler( MouseWheelHandler handler )
{
return addMouseWheelHandler( handler );
}
/* (non-Javadoc)
* @see com.google.gwt.user.client.ui.HasHTML#getHTML()
*/
@Override
public String getHTML()
{
return getElement().getInnerHTML();
}
/* (non-Javadoc)
* @see com.google.gwt.user.client.ui.HasHTML#setHTML(java.lang.String)
*/
@Override
public void setHTML( String html )
{
remove( text );
insert( text, 1 );
}
/* (non-Javadoc)
* @see com.google.gwt.user.client.ui.HasText#getText()
*/
@Override
public String getText()
{
return text.getText();
}
/* (non-Javadoc)
* @see com.google.gwt.user.client.ui.HasText#setText(java.lang.String)
*/
@Override
public void setText( String text )
{
this.text.setText( text );
}
/* (non-Javadoc)
* @see com.google.gwt.safehtml.client.HasSafeHtml#setHTML(com.google.gwt.safehtml.shared.SafeHtml)
*/
@Override
public void setHTML( SafeHtml html )
{
setHTML( html.asString() );
}
}
Extiende el DialogBox para usar el nuevo ButtonCaption disponible
class CaptionCloseableDialogBox extends DialogBox
{
public CaptionCloseableDialogBox()
{
super( new ButtonCaption( "dialog box title" ) );
setAutoHideEnabled( false );
ButtonCaption ref = (ButtonCaption) this.getCaption();
PushButton closeButton = ref.getCloseButton();
// apply button face here closeButton;
closeButton.addClickHandler( /* attach any click handler here like close this dialog */ );
}
}
Espero que ayude a cualquiera.
Una solución más simple es usar gwt-ext ( http://code.google.com/p/gwt-ext/ ). Es gratis y fácil de usar e integrar. Puedes ver su showcase http://www.gwt-ext.com/demo/ . Creo que lo que quieres es la ventana de MessageBox o Layout (están en la categoría de Windows del escaparate).
Saludos.
Usamos GWT-ext desde el principio en nuestro proyecto. Fue una mala idea Tienen muchos widgets geniales, pero no son widgets GWT Y no tienen compatibilidad con widgets GWT. Una vez que elija GWT-Ext, todo, incluso el mecanismo de evento, debe estar en el modo GWT-Ext, no en el modo GWT. Esta biblioteca no se actualizará para la versión más nueva de GWT, porque la biblioteca javascript Ext no es más gratuita. Estamos eliminando GWT-Ext de nuestro proyecto ahora.
No es posible agregar un widget diferente en el título GWT DialogBox, pero puede extender "DecoratedPanel" (es el elemento principal DialogBox). Mire la fuente DialogBox para aprender las técnicas, especialmente cómo agrega el objeto Subtítulo al panel y cómo se implementa el arrastre de la ventana.
Eso es lo que hemos hecho aquí, y funciona muy bien. Hemos creado nuestra propia clase Caption que extiende FocusablePanel (un SimplePanel que captura todos los eventos del mouse) y le hemos agregado un HorizontalPanel, con botones y texto. Tuvimos que anular onAttach () y onDetach () simplemente llamando al método super (están protegidos).
Creo que no puedo poner nuestro código fuente aquí, así que puedo darte estos consejos.
sí hay
No, no, al menos no sin tocar la clase DialogBox de GWT o recreando el DialogBox utilizando widgets comunes. Este es un problema conocido en GWT, también conocido como el problema 1405 (ejecútelo para mostrar su interés).
Sin embargo; DialogBox no nos da las herramientas para hacer esto, así que necesitamos extenderlo - Editar: esto no funciona.
Si desea hacer un reemplazo directo para DialogBox, puede asignarle un nombre a su clase DialogBox e importarlo en lugar del que se incluye en GWT. Este hilo en el foro de GWT brinda más detalles sobre cómo se puede hacer esto (obsoleto, usa oyentes). Desactualizado, las partes internas de DialogBox han cambiado mucho desde este hilo; no funciona.
Aquí hay un código que pirateé para obtener los mismos resultados (utilicé el hilo vinculado como guía) . Esto no funciona:
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();
}
Nota: Este código no funciona. ClickEvent no se envía desde la cross
sino desde MyDialogBox, independientemente de si agrega ClickHandlers a la cross
o no, IOW MyDialogBox es el remitente / fuente y, por lo tanto, no es posible verificar contra cross
. Cuando se hace clic en la cruz, no se activa ClickEvent por algún motivo.
Editar: parece que esto no se puede hacer sin hacks a menos que escribas tu propio DialogBox (casi) desde cero o arregles el problema 1405. Por supuesto, hay varias bibliotecas existentes que ya han resuelto este problema, es decir, SmartGWT y GWT-Ext , pero su implementación se realiza principalmente desde cero.
Entonces, para responder a tu pregunta en una frase: Sí, hay una manera, pero no te va a gustar :)