Vaadin 8.5.1-行更新后刷新网格

我正在使用Vaadin 8.5.1 Grid来显示1000行。 一旦更新了属性的更新行,我使用grid.getDataProvider().refreshItem(selectedRow)grid.getDataProvider().refreshAll()无法更新行。

我需要显式grid.setItems()来查看行的更新属性。

我正在使用下面的代码片段来创建一个Grid

  msgGrid = new ABSMsgGrid(); List messageEntryList = new ArrayList(); if (inputConsole != null) { messageEntryList.addAll(inputConsole.getMessageEntryList()); } msgGridDataProvider = new ListDataProvider(messageEntryList) { @Override public Object getId(ConsoleEntry item) { return item.getId(); } }; msgGrid.setDataProvider(msgGridDataProvider); //on changing property of the grid row, i use the below snippet private void handleHideRowMenuItem(GridContextMenu contextMenu, ConsoleEntry selectedConsoleItem) { if (!selectedConsoleItem.isHidden()) { hideRowMenuItem = contextMenu.addItem("Hide Row", VaadinIcons.EYE_SLASH, selectedMenuItem -> { selectedConsoleItem.hide(); **msgGridDataProvider.refreshItem(selectedConsoleItem);** } }); } } public class ConsoleEntry { @Override public boolean equals(Object obj) { // TODO Auto-generated method stub if (obj instanceof ConsoleEntry) { ConsoleEntry temp = (ConsoleEntry) obj; String msgRef2 = temp.getMsgRef(); return this.getMsgRef().equalsIgnoreCase(msgRef2); } return false; } @Override public int hashCode() { // TODO Auto-generated method stub return super.hashCode(); } public String getId(){ return this.getMsgRef(); } } 

我见过类似的问题,但没有一个解决方案有效。

如何在更改内容后刷新vaadin Grid?

Vaadin – 行修改后刷新网格

感谢是否有人可以分享如何解决这个问题的指示

TIA

对于要被视为相同项目的项目(以及刷新工作),您需要在对象上使用相应的equals()hashCode()方法。

从文档中

public void refreshItem(T item)

从interface:DataProvider复制的描述

刷新给定项目。 此方法应用于通知所有DataProviderListener项已更新或替换为新实例。

为了使其正常工作,该项必须实现

equals(Object)和#hashCode()将旧项和新项实例视为相等,或者替代

应该实现DataProvider.getId(Object)以返回适当的标识符。

除此之外,您应该创建一个ListDataProvider ,将其分配给网格,然后通过先前分配的ListDataProvider的相同实例进行更新。

正如Schild所说的正确答案 ,你必须覆盖你的equalshashCode方法,以便他们考虑相同的字段,并且他们必须只考虑在你的时间范围内其值不会改变的字段。依靠他们。

对于数据驱动的业务对象,这通常意味着只需查看对象上的标识符,该对象是数据库中的主键(或者如果您使用数据库)。

如下例所示,我们的Status类有一个UUID对象作为其标识符,一个通用唯一标识符(UUID) (128位值,规范显示为带有连字符的36个字符的hex字符串)。 我们的equalshashCode只考虑该对象的一个​​成员。

 @Override public boolean equals ( Object obj ) { // Compare the UUID member named `uuid`. if ( obj == this ) { return true; } if ( obj instanceof Status ) { return this.getUuid().equals( ( ( Status ) obj ).getUuid() ); } return false; } @Override public int hashCode () { return Objects.hashCode( this.uuid ); } // Compare the UUID member named `uuid`. 

示例应用

这是一个完整的工作示例。 写于Vaadin 8.5。

在此处输入图像描述

在这个例子中,我们跟踪三件设备。 Status对象代表每个。

我们通过从弹出菜单中选择一个新的值编号(Vaadin中的NativeSelect ),然后单击一个设备的按钮来修改当前状态编号(-1,0或1)。 选择一行与此无关。

为了您的启发,我编写了两个不同的代码片段来更新Grid的项目。 这两种方法在Vaadin商业应用中很常见:

  • 修改支持Grid的现有Status对象。
  • 用新实例替换目标Status对象,但在其id字段中使用相同的标识符值。

例如,在某些情况下,可以编写数据存储库服务代码以始终返回新的实例。 在其他情况下,我们可能会故意更新现有对象。

  private void updateByModifying ( Status s , Integer integer ) { s.setCurrentStatus( integer ); grid.getDataProvider().refreshItem( s ); } private void updateByInstantiating ( Status s , Integer integer ) { boolean removed = statuses.remove( s ); Status replacement = new Status( s.getUuid() , s.getName() , integer ); boolean added = statuses.add( replacement ); grid.getDataProvider().refreshItem( replacement ); } 

在此演示中,使用“ Update row by弹出菜单(也称为下拉列表)在这些方法之间切换。 这两种方法都可以通过调用DataProvider::refreshItem 。 请注意,这两种方法都取决于您的equalshashCode是否正确实现。

作为另一个例子,我抛出了一个Refresh all按钮来显示DataProvider::refreshAll方法的使用。

源代码

此示例应用程序中有三个Java文件:

  • MyUI.java (进入Vaadin)
  • Status.java (我们的业务对象,POJO)
  • StatusLayout (UI内容和业务逻辑)

MyUI.java

 package com.basilbourque.example; import javax.servlet.annotation.WebServlet; import com.vaadin.annotations.Theme; import com.vaadin.annotations.VaadinServletConfiguration; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinServlet; import com.vaadin.ui.*; import java.util.List; import java.util.UUID; /** * This UI is the application entry point. A UI may either represent a browser window * (or tab) or some part of an HTML page where a Vaadin application is embedded. * 

* The UI is initialized using {@link #init(VaadinRequest)}. This method is intended to be * overridden to add component to the user interface and initialize non-component functionality. */ @Theme ( "mytheme" ) public class MyUI extends UI { @Override protected void init ( VaadinRequest vaadinRequest ) { Layout layout = new StatusLayout(); this.setContent( layout ); } @WebServlet ( urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true ) @VaadinServletConfiguration ( ui = MyUI.class, productionMode = false ) public static class MyUIServlet extends VaadinServlet { } }

Status.java

 package com.basilbourque.example; import java.util.Objects; import java.util.UUID; public class Status { // Members. private UUID uuid; private String name; private Integer currentStatus; // 1 = Good, 0 = okay, -1 = Bad. // Constructor. public Status ( UUID uuid , String name , Integer currentStatus ) { this.uuid = uuid; this.name = name; this.currentStatus = currentStatus; } // -----------| Object |------------------------- @Override public boolean equals ( Object obj ) { // Compare the UUID member named `uuid`. if ( obj == this ) { return true; } if ( obj instanceof Status ) { return this.getUuid().equals( ( ( Status ) obj ).getUuid() ); } return false; } @Override public int hashCode () { return Objects.hashCode( this.uuid ); } // Compare the UUID member named `uuid`. @Override public String toString () { return "Status{ " + "uuid=" + uuid + " | name='" + name + '\'' + " | currentStatus=" + currentStatus + " }"; } // -----------| Accessors |----------------------------- public UUID getUuid () { return uuid; } public void setUuid ( UUID uuid ) { this.uuid = uuid; } public String getName () { return name; } public void setName ( String name ) { this.name = name; } public Integer getCurrentStatus () { return currentStatus; } public void setCurrentStatus ( Integer currentStatus ) { this.currentStatus = currentStatus; } } 

StatusLayout.java

 package com.basilbourque.example; import com.vaadin.data.provider.ListDataProvider; import com.vaadin.ui.*; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; public class StatusLayout extends VerticalLayout { // Members List< Status > statuses; Grid< Status > grid; final List< Integer > numbers = List.of( 1 , 0 , - 1 ); NativeSelect< Integer > numberPopup; NativeSelect< Boolean > updatyByModifyingOrInstantiating; Button setPump, setCamera, setSensor, refreshAllButton; // Constructor public StatusLayout () { statuses = new ArrayList<>( 3 ); statuses.add( new Status( UUID.fromString( "1c0d183e-c2ba-11e8-a355-529269fb1459" ) , "Pump" , numbers.get( 0 ) ) ); statuses.add( new Status( UUID.fromString( "2490c74e-1aac-4d71-9a2c-880628dcfc28" ) , "Camera" , numbers.get( 1 ) ) ); statuses.add( new Status( UUID.fromString( "6ae07414-f557-4a1e-a552-cb5ec5f48476" ) , "Sensor" , numbers.get( 2 ) ) ); // Create a grid bound to the list grid = new Grid<>( Status.class ); grid.setCaption( "Equipment Status" ); grid.setItems( statuses ); // grid.addColumn( Status :: getName ).setCaption( "Name" ); // grid.addColumn( Status :: getCurrentStatus ).setCaption( "Status" ); updatyByModifyingOrInstantiating = new NativeSelect<>( "Update row by: " , List.of( Boolean.TRUE , Boolean.FALSE ) ); updatyByModifyingOrInstantiating.setValue( Boolean.TRUE ); updatyByModifyingOrInstantiating.setItemCaptionGenerator( ( ItemCaptionGenerator< Boolean > ) item -> item ? "modifying" : "instantiating" ); Label valueSetterLabel = new Label( "Set status:" ); numberPopup = new NativeSelect<>(); numberPopup.setItems( numbers ); numberPopup.setValue( numbers.get( 1 ) ); // numberPopup.setItemCaptionGenerator( item -> List.of( "Good" , "Okay" , "Bad" ).get( numbers.indexOf( item ) ) ); // Display words rather than the underlying number. // The `buttonClick` method below has logic depending on match between button name and `name` property on `Status` objects in grid. setPump = new Button( statuses.get( 0 ).getName() ); // Pump setPump.addClickListener( this :: buttonClick ); setCamera = new Button( statuses.get( 1 ).getName() ); // Camera setCamera.addClickListener( this :: buttonClick ); setSensor = new Button( statuses.get( 2 ).getName() ); // Sensor setSensor.addClickListener( this :: buttonClick ); refreshAllButton = new Button( "Refresh all" ); refreshAllButton.addClickListener( clickEvent -> grid.getDataProvider().refreshAll() ); // Arrange grid.setWidth( 100 , Unit.PERCENTAGE ); HorizontalLayout valueSetterBar = new HorizontalLayout(); valueSetterBar.addComponents( valueSetterLabel , numberPopup , setPump , setCamera , setSensor ); valueSetterBar.setComponentAlignment( valueSetterLabel , Alignment.MIDDLE_CENTER ); valueSetterBar.setComponentAlignment( numberPopup , Alignment.MIDDLE_CENTER ); valueSetterBar.setComponentAlignment( setPump , Alignment.MIDDLE_CENTER ); valueSetterBar.setComponentAlignment( setCamera , Alignment.MIDDLE_CENTER ); valueSetterBar.setComponentAlignment( setSensor , Alignment.MIDDLE_CENTER ); addComponents( grid , updatyByModifyingOrInstantiating , valueSetterBar , refreshAllButton ); } private void buttonClick ( Button.ClickEvent clickEvent ) { System.out.println( "TRACE - Setting " + clickEvent.getButton().getCaption() + " to " + this.numberPopup.getValue().toString() ); // Find the `Status` object in the `List` whose name matches the name of the button clicked by user. Optional< Status > optionalStatus = statuses.stream().filter( status -> status.getName().equals( clickEvent.getButton().getCaption() ) ).findFirst(); // We expect the matching `Status` to always be found. If not, throw exception. Status s = optionalStatus.orElseThrow( () -> new IllegalStateException( "Failed to find expected item in list of statuses: " + clickEvent.getButton().getCaption() ) ); Integer valueToSet = this.numberPopup.getValue(); // Set the `currentStatus` property on the `Status` object to the value of the selected popup menu item. // Try either updating by modifying existing row or by instantiating a new one. // Comment-out either of the next two lines. if(updatyByModifyingOrInstantiating.getValue().equals( Boolean.TRUE )) { this.updateByModifying( s , valueToSet ); } else { this.updateByInstantiating( s , valueToSet ); } } private void updateByModifying ( Status s , Integer integer ) { s.setCurrentStatus( integer ); grid.getDataProvider().refreshItem( s ); } private void updateByInstantiating ( Status s , Integer integer ) { boolean removed = statuses.remove( s ); Status replacement = new Status( s.getUuid() , s.getName() , integer ); boolean added = statuses.add( replacement ); grid.getDataProvider().refreshItem( replacement ); } }