为Vaadin 8 Grid实现列渲染器

时间:2017-08-29 16:55:36

标签: datagrid vaadin renderer vaadin8

Vaadin Framework指南在page describing how to use Column Renderers中有一个Vaadin Grid。和this page describes implementing renderers,但都过于简短。

我想实现一个InstantRenderer来补充Vaadin 8.1中添加的部分java.time渲染器。为LocalDate&添加了渲染器LocalDateTime但不适用于InstantOffsetDateTimeZonedDateTime。对于我的Instant渲染器,我目前只是应用当前的默认时区(ZoneId)来获取ZonedDateTime,我称之为toString方法。可以做得更多,但这只是为了开始。

所以我的代码应该与提供的LocalDateTimeRenderer非常相似。我试图遵循该代码作为指导。

在搜索Vaadin源代码并阅读文档时,我似乎需要三个源代码:

我已经完成了这一切,并且全部编译完毕。但我的桌子无法渲染,我得到的只是页面上的一个白色空盒子。控制台或日志中不会显示任何错误。如果我删除了对InstantRenderer的使用,并回退让我的Instant对象通过默认的toString方法进行渲染,则表示一切正常,表格按预期显示。所以我知道我的自定义渲染器有问题。

对于"服务器端"我是新手。 vs"客户端" Vaadin。

➠我需要进行某种包装吗?目前,我的Vaadin项目中有三个类和MyUI源文件一起。

➠我错过了其他一些作品吗?

我通过调用no-arg构造函数来实例化我的渲染器:

this.entriesGrid
    .addColumn( Entry::getStart )
    .setCaption( "Start" )
    .setRenderer( new InstantRenderer(  ) )
;

以上是我上面列出的三个文件,几乎全部来自Vaadin源代码。

InstantRenderer

/*
 * By Basil Bourque. Taken almost entirely from source code published by Vaadin Ltd.
 *
 * --------
 *
 * Copyright 2000-2016 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.basil.timepiece;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;

import java.util.Locale;

import elemental.json.JsonValue;

/**
 * A renderer for presenting {@code Instant} objects.
 *
 * @author Vaadin Ltd
 * @since 8.1
 */
public class InstantRenderer
        extends com.vaadin.ui.renderers.AbstractRenderer< Object, Instant >
{
    private DateTimeFormatter formatter;
    private boolean getLocaleFromGrid;

    private ZoneId zoneId = ZoneId.systemDefault(); // Basil Bourque.

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the grid's locale it is
     * attached to, with the format style being {@code FormatStyle.LONG} for the
     * date and {@code FormatStyle.SHORT} for time, with an empty string as its
     * null representation.
     *
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/FormatStyle.html#LONG">
     * FormatStyle.LONG</a>
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/FormatStyle.html#SHORT">
     * FormatStyle.SHORT</a>
     */
    public InstantRenderer ()
    {
        this( DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG , FormatStyle.SHORT ) , "" );
        getLocaleFromGrid = true;
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given formatter, with the
     * empty string as its null representation.
     *
     * @param formatter the formatter to use, not {@code null}
     * @throws IllegalArgumentException if formatter is null
     */
    public InstantRenderer ( DateTimeFormatter formatter )
    {
        this( formatter , "" );
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given formatter.
     *
     * @param formatter          the formatter to use, not {@code null}
     * @param nullRepresentation the textual representation of the {@code null} value
     * @throws IllegalArgumentException if formatter is null
     */
    public InstantRenderer ( DateTimeFormatter formatter , String nullRepresentation )
    {
        super( Instant.class , nullRepresentation );

        if ( formatter == null )
        {
            throw new IllegalArgumentException( "formatter may not be null" );
        }

        this.formatter = formatter;
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given string format, as
     * displayed in the grid's locale it is attached to, with an empty string as
     * its null representation.
     *
     * @param formatPattern the format pattern to format the date with, not {@code null}
     * @throws IllegalArgumentException if format pattern is null
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns">
     * Format Pattern Syntax</a>
     */
    public InstantRenderer ( String formatPattern )
    {
        this( formatPattern , Locale.getDefault() );
        getLocaleFromGrid = true;
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given string format, as
     * displayed in the given locale, with an empty string as its null
     * representation.
     *
     * @param formatPattern the format pattern to format the date with, not {@code null}
     * @param locale        the locale to use, not {@code null}
     * @throws IllegalArgumentException if format pattern is null
     * @throws IllegalArgumentException if locale is null
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns">
     * Format Pattern Syntax</a>
     */
    public InstantRenderer ( String formatPattern , Locale locale )
    {
        this( formatPattern , locale , "" );
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given string format, as
     * displayed in the given locale.
     *
     * @param formatPattern      the format pattern to format the date with, not {@code null}
     * @param locale             the locale to use, not {@code null}
     * @param nullRepresentation the textual representation of the {@code null} value
     * @throws IllegalArgumentException if format pattern is null
     * @throws IllegalArgumentException if locale is null
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns">
     * Format Pattern Syntax</a>
     */
    public InstantRenderer ( String formatPattern , Locale locale , String nullRepresentation )
    {
        super( Instant.class , nullRepresentation );

        if ( formatPattern == null )
        {
            throw new IllegalArgumentException( "format pattern may not be null" );
        }

        if ( locale == null )
        {
            throw new IllegalArgumentException( "locale may not be null" );
        }

        formatter = DateTimeFormatter.ofPattern( formatPattern , locale );
    }

    @Override
    public JsonValue encode ( Instant value )
    {
        String dateString;
        if ( value == null )
        {
            dateString = this.getNullRepresentation();
        } else if ( this.getLocaleFromGrid )
        {
            if ( null == this.getParentGrid() )
            {
                throw new IllegalStateException(
                        "Could not find a locale to format with: "
                                + "this renderer should either be attached to a grid "
                                + "or constructed with locale information" );
            }
            ZonedDateTime zdt = value.atZone( this.zoneId );  // Basil Bourque.
            Locale locale = this.getParentGrid().getLocale();
            dateString = zdt.format( formatter.withLocale( locale ) );
        } else
        {
            ZonedDateTime zdt = value.atZone( this.zoneId );  // Basil Bourque.
            dateString = zdt.format( formatter );
        }
        return encode( dateString , String.class );
    }

    @Override
    protected InstantRendererState getState ()
    {
        InstantRendererState s = ( InstantRendererState ) super.getState();
        return s;
    }

    @Override
    protected InstantRendererState getState ( boolean markAsDirty )
    {
        InstantRendererState s = ( InstantRendererState ) super.getState( markAsDirty );
        return s;
    }
}

InstantRendererConnector

/*
 * By Basil Bourque. Taken almost entirely from source code published by Vaadin Ltd.
 *
 * --------
 *
 * Copyright 2000-2016 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.basil.timepiece;

import com.vaadin.shared.ui.Connect;

/**
 * A connector for InstantRenderer.
 * <p>
 * The server-side Renderer operates on {@code Instant}s, but the data is
 * serialized as a string, and displayed as-is on the client side. This is to be
 * able to support the server's locale.
 *
 * @author Vaadin Ltd
 * @since 8.1
 */
@Connect( InstantRenderer.class )
public class InstantRendererConnector extends com.vaadin.client.connectors.grid.TextRendererConnector
{

    @Override
    public InstantRendererState getState ()
    {
        return ( InstantRendererState ) super.getState();
    }
}

InstantRendererState

/*
 * By Basil Bourque. Taken almost entirely from source code published by Vaadin Ltd.
 *
 * --------
 *
 * Copyright 2000-2016 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.basil.timepiece;

/**
 * Shared state of InstantRenderer.
 *
 * @author Vaadin Ltd
 * @since 8.1
 */
public class InstantRendererState extends com.vaadin.shared.ui.grid.renderers.TextRendererState
{
    // This code intentionally left blank.
}

BitBucket上的源

我已发布了complete Maven-driven project on BitBucketInstantOffsetDateTimeZonedDateTime的列渲染器的所有必要文件。

功能请求

我在Vaadin Framework GitHub页面上发布了Issue # 10208 Implement column renderers for Vaadin Grid for other java.time types (Instant, OffsetDateTime, ZonedDateTime) to complement the LocalDate & LocalDateTime renderers in Vaadin 8.1.

1 个答案:

答案 0 :(得分:1)

需要特殊包装

是的,需要特殊包装。您不能简单地将Vaadin Grid column renderer implementation类投入常规的Vaadin应用程序。

列渲染器实现所需的三个类中有两个涉及client-side development,而不是我们在Vaadin应用程序中常用的server-side development

幸运的是,这比听起来容易。为了做一个简单的列渲染器,Vaadin幸运地提供了一些可以完成大部分繁重任务的超级类。因此,我们无需了解Vaadin隐藏的GWTJavaScript魔法的所有血腥细节。

成功之路涉及:

vaadin-archetype-widget

使用Vaadin小组提供的multi-module Maven archetype开始一个新项目:vaadin-archetype-widgetthis list

screen shot of IntelliJ > New Project > Create from archetype dialog box

addon模块

IDE中根据该原型创建项目后,添加三个列渲染器类,如此Instant渲染器的屏幕截图所示。

  • Renderer课程在'addon'模块的主程序包中。
  • RendererConnector&amp; RendererState类文件放在'addon'模块的嵌套client包中。

当然,在实际工作中,您将删除由原型创建的示例MyComponent…文件。

demo模块

构建完成后,您可以通过导入“addon”模块的包在“demo”模块的Vaadin应用程序中尝试列渲染器。在这种情况下:

import org.basilbourque.timecolrenderers.InstantRenderer;

GitHub来源

我成功实现Instant列渲染器完全取自Vaadin 8.1.3源代码提供的三个LocalDateTimeRenderer相关类。您可以在GitHub find file feature中输入LocalDateTimeRenderer来找到这些类的当前版本。

enter image description here

screen shot of 'Project' pane in IntelliJ showing the position of three Java source files within the package hierarchy