Ajuda com método UPDATE (Vaadin + SpringBoot + MySQL)

Bom dia a todos.

Tenho um sistema de registro de produtos, onde o usuário pode registrar produtos, excluir produtos, ler produtos e atualizar produtos. UM CRUD

Estou tendo problemas para atualizar, as outras operações estão bem.

Vamos ao problema.

VEJA A IMAGEM

Como mostrado na imagem, o usuário registrou uma placa de vídeo, marca Asus, modelo gto com o valor 3000

Agora o usuário precisa alterar o valor para 2500

para isso, ele segue os seguintes procedimentos

clique no produto a ser atualizado, o botão de edição será ativado, ele clica no botão de edição, todos os campos do produto se tornam editáveis (menos o id), o usuário altera o valor para 2500.

Até agora tudo está dando certo, o problema é que depois que o usuário altera o valor, ou qualquer outra informação, essa mudança deve ser confirmada apenas pressionando ENTER, mas não é o que está acontecendo.

Para confirmar a alteração/atualização neste momento o usuario está fazendo as seguintes etapas:

1º TECLA ENTER
2º CLICA NO BOTÃO EDITAR
3º MESMO APÓS CLICAR EM EDITAR, OS CAMPOS PERMANECEM EM ESTADO DE EDIÇÃO
4º TENHO QUE PRESSIONAR F5
5º APÓS ESTES PASSOS, AI SIM A ATUALIZAÇÃO É CONFIRMADA

o comportamento desejado é, para confirmar a atualização do produto basta ser o teclado ENTER e depois disso a grade é atualizada sem pressionar o botão de edição ou F5

Deveria ser assim para atualizar:

1º TECLA ENTER APÓS ALTERAR O CAMPO DESEJADO.

Veja que em vez de 5 etapas, quero apenas 1 etapa

Como alcançar esse comportamento?

Vou postar os códigos das classes para que possam dar uma olhada…muito obrigado!!

package br.com.fjsistemas.backend;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Produto {
	

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	private String nome;
	private String marca;
	private String modelo;
	private Double valor;

}

MINHA VIEW

package br.com.fjsistemas.cadastros.view;

    import java.util.List;
    import java.util.Locale;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;

    import com.vaadin.flow.component.Text;
    import com.vaadin.flow.component.button.Button;
    import com.vaadin.flow.component.button.ButtonVariant;
    import com.vaadin.flow.component.dialog.Dialog;
    import com.vaadin.flow.component.grid.Grid;
    import com.vaadin.flow.component.grid.GridVariant;
    import com.vaadin.flow.component.html.Div;
    import com.vaadin.flow.component.icon.Icon;
    import com.vaadin.flow.component.icon.VaadinIcon;
    import com.vaadin.flow.component.notification.Notification;
    import com.vaadin.flow.component.notification.Notification.Position;
    import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
    import com.vaadin.flow.component.textfield.TextField;
    import com.vaadin.flow.data.binder.Binder;
    import com.vaadin.flow.data.converter.StringToDoubleConverter;
    import com.vaadin.flow.data.renderer.NumberRenderer;
    import com.vaadin.flow.router.PageTitle;
    import com.vaadin.flow.router.Route;
    import com.vaadin.flow.router.RouteAlias;
    import com.vaadin.flow.spring.annotation.UIScope;

    import br.com.fjsistemas.backend.Produto;
    import br.com.fjsistemas.main.MainView;
    import br.com.fjsistemas.service.ProdutoService;

    @Route(value = "cadastroproduto", layout = MainView.class)
    @PageTitle("Cadastro de Produtos")
    @RouteAlias(value = "Cadastro Produtos", layout = MainView.class)
    @Component
    @UIScope
    public class CadastroProduto extends Div {

    	private static final long serialVersionUID = 1L;

    	private List<Produto> lista;
    	private Grid<Produto> grid;

    	private final Button remover;
    	private final Button adicionar;
    	private final Button edit;

    	private Produto produtoAtual;
    	
    	private final Binder<Produto> janelaBinder = new Binder<>(Produto.class);
    	private final Binder<Produto> gridBinder = new Binder<>(Produto.class);

    	private final TextField gridTxtNome = new TextField();
    	private final TextField gridTxtMarca = new TextField();
    	private final TextField gridTxtModelo = new TextField();
    	private final TextField gridTxtValor = new TextField();

    	private ProdutoService produtoService;

    	@Autowired
    	public CadastroProduto(ProdutoService produtoService) {
    		this.produtoService = produtoService;
    		addGrid();

    		Dialog janela = getEditDialog();

    		adicionar = new Button(new Icon(VaadinIcon.PLUS_CIRCLE_O));
    		adicionar.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
    		adicionar.addClickListener(event -> janela.open());

    		remover = new Button(new Icon(VaadinIcon.MINUS_CIRCLE_O));
    		remover.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
    		remover.addClickListener(event -> {
    			if (produtoAtual != null) {
    				produtoService.delete(produtoAtual);
    				lista.remove(produtoAtual);
    				grid.setItems(lista);
    				produtoAtual = null;
    				enableEditingButtons(false);
    			}
    		});

    		edit = new Button(new Icon(VaadinIcon.EDIT));
    		edit.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
    		edit.addClickListener(e -> {
    			grid.getEditor().editItem(produtoAtual);
    			gridTxtNome.focus();
    			gridTxtMarca.focus();
    			gridTxtModelo.focus();
    			gridTxtValor.focus();
    			produtoService.update(produtoAtual);

    		});

    		enableEditingButtons(false);
    		HorizontalLayout layoutInterno2 = new HorizontalLayout();
    		layoutInterno2.add(adicionar, remover, edit);
    		add(layoutInterno2);
    	}

    	private Dialog getEditDialog() {
    		Dialog janela = new Dialog();

    		janela.setCloseOnEsc(false);
    		janela.setCloseOnOutsideClick(false);
    		janela.setWidth("700px");
    		janela.setHeight("360px");

    		HorizontalLayout layoutJanelaInterno1 = new HorizontalLayout();

    		Text titulo = new Text("Novo Produto");

    		HorizontalLayout layoutJanelaInterno2 = new HorizontalLayout();

    		TextField nome = new TextField("Produto:");
    		nome.setMinWidth("50%");

    		TextField marca = new TextField("Marca:");
    		marca.setMinWidth("50%");

    		HorizontalLayout layoutJanelaInterno3 = new HorizontalLayout();

    		TextField modelo = new TextField("Modelo:");
    		modelo.setWidth("50%");

    		TextField valor = new TextField("Valor Unitário:");
    		valor.setWidth("50%");

    		layoutJanelaInterno1.add(titulo);
    		layoutJanelaInterno1.setMargin(isVisible());
    		layoutJanelaInterno2.add(nome, marca);
    		layoutJanelaInterno2.setMargin(isVisible());
    		layoutJanelaInterno3.add(modelo, valor);
    		layoutJanelaInterno3.setMargin(isVisible());

    		janelaBinder.forField(nome).withConverter(String::toUpperCase, String::valueOf, " ").bind(Produto::getNome,
    				Produto::setNome);

    		janelaBinder.forField(marca).withConverter(String::toUpperCase, String::valueOf, " ").bind(Produto::getMarca,
    				Produto::setMarca);

    		janelaBinder.forField(modelo).withConverter(String::toUpperCase, String::valueOf, " ").bind(Produto::getModelo,
    				Produto::setModelo);

    		janelaBinder.forField(valor).withConverter(new StringToDoubleConverter(0.0, "Valor Inválido"))
    				.withNullRepresentation(0.0).bind(Produto::getValor, Produto::setValor);

    		HorizontalLayout layoutBotoes = new HorizontalLayout();

    		Button salvar = new Button("Salvar");
    		salvar.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
    		salvar.getStyle().set("margin-top", "25px");
    		salvar.addClickListener(event -> {
    			Produto produtoNovo = new Produto();

    			lista.add(produtoNovo);

    			grid.setItems(lista);

    			janelaBinder.writeBeanIfValid(produtoNovo);
    			produtoService.create(produtoNovo);
    			janelaBinder.readBean(new Produto(null, " ", " ", " ", null));
    			janelaBinder.getFields().forEach(f -> f.clear());

    		});

    		Button fechar = new Button("Fechar");
    		fechar.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
    		fechar.getStyle().set("margin-top", "25px");
    		fechar.addClickListener(event -> {
    			janela.close();
    		});

    		janela.add(layoutJanelaInterno1);
    		janela.add(layoutJanelaInterno2);
    		janela.add(layoutJanelaInterno3);
    		janela.add(layoutBotoes);

    		layoutBotoes.add(salvar, fechar);
    		return janela;
    	}

    	private void enableEditingButtons(boolean enable) {
    		remover.setEnabled(enable);
    		edit.setEnabled(enable);
    	}

    	private void addGrid() {

    		lista = produtoService.read();
    		grid = new Grid<>();

    		grid.setItems(lista);
    		grid.setHeight("835px");

    		grid.addColumn(Produto::getId).setHeader("ID:").setAutoWidth(true);

    		grid.addColumn(Produto::getNome).setHeader("Produto:").setAutoWidth(true).setKey("nome");

    		grid.addColumn(Produto::getMarca).setHeader("Marca:").setAutoWidth(true).setKey("marca");

    		grid.addColumn(Produto::getModelo).setHeader("Modelo:").setAutoWidth(true).setKey("modelo");

    		grid.addColumn(new NumberRenderer<>(Produto::getValor, "R$ %(,.2f", Locale.getDefault(), "R$ 0.00"))
    				.setHeader("Valor Unitário:").setAutoWidth(true).setKey("valor");

    		grid.addThemeVariants(GridVariant.LUMO_COMPACT, GridVariant.LUMO_COLUMN_BORDERS);

    		grid.asSingleSelect().addValueChangeListener(e -> {
    			produtoAtual = e.getValue();
    			enableEditingButtons(e.getValue() != null);
    		});

    		grid.getEditor().setBinder(gridBinder);

    		gridTxtNome.getElement().addEventListener("keydown", event -> grid.getEditor().cancel())
    				.setFilter("event.key === 'Enter'");

    		gridTxtMarca.getElement().addEventListener("keydown", event -> grid.getEditor().cancel())
    				.setFilter("event.key === 'Enter'");

    		gridTxtModelo.getElement().addEventListener("keydown", event -> grid.getEditor().cancel())
    				.setFilter("event.key === 'Enter'");

    		gridTxtValor.getElement().addEventListener("keydown", event -> grid.getEditor().cancel())
    				.setFilter("event.key === 'Enter'");

    		gridBinder.forField(gridTxtNome).withConverter(String::toUpperCase, String::valueOf, " ").bind("nome");
    		grid.getColumnByKey("nome").setEditorComponent(gridTxtNome);

    		gridBinder.forField(gridTxtMarca).withConverter(String::toUpperCase, String::valueOf, " ").bind("marca");
    		grid.getColumnByKey("marca").setEditorComponent(gridTxtMarca);

    		gridBinder.forField(gridTxtModelo).withConverter(String::toUpperCase, String::valueOf, " ").bind("modelo");
    		grid.getColumnByKey("modelo").setEditorComponent(gridTxtModelo);

    		gridBinder.forField(gridTxtValor).withConverter(new StringToDoubleConverter("Número Inválido")).bind("valor");
    		grid.getColumnByKey("valor").setEditorComponent(gridTxtValor);

    		grid.getEditor().addCloseListener(event -> {
    			if (gridBinder.getBean() != null) {
    				Notification.show("Texto Alterado!", 1000, Position.TOP_END);

    			}
    		});
    		add(grid);
    	}
    }
package br.com.fjsistemas.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import br.com.fjsistemas.backend.Produto;


public interface ProdutoRepository extends JpaRepository<Produto, Long> {

	
}
package br.com.fjsistemas.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import br.com.fjsistemas.backend.Produto;
import br.com.fjsistemas.repository.ProdutoRepository;

@Service
public class ProdutoService {

	// CRUD

	@Autowired
	private ProdutoRepository produtoRepository;

	public void create(Produto produto) {
		produtoRepository.save(produto);
	}

	public List<Produto> read() {
		List<Produto> produtos = produtoRepository.findAll();
		return produtos;

	}

	public void update(Produto produto) {
		produtoRepository.save(produto);
	}

	public void delete(Produto produto) {
		produtoRepository.delete(produto);
	}
}

up

Utilize algum evento Listener, aconselho usar o keypress e verificar se a key foi o enter, então executar o processo de atualizar que é executado ao dar F5. Sendo assim quando o usuario pressionar enter já vai atualizar.

Gabriel, obrigado por sua resposta, mas se não for pedir muito, teria como você codificar para que eu possa entender melhor?

public void VerificaTeclaPressionada() {
key = KeyEvent.KEY_PRESSED;
if (key == KeyEvent.VK_ENTER) {
  System.out.print(“enter apertado\n”);
} 
}

± isso, estou pelo celular então não da pra fazer muita coisa, mas é algo bem simples tem vários tutoriais na internet.

Gabriel, obrigado por sua ajuda, mas não deu certo…o comportamento continua o mesmo