I have a Vaadin tab menu, each tab contains of course different content. Now, if the content is an own class with dynamically generated content, how can I force the content to be updated if a tab is selected?
My content class implements View, thus it as a enter(ViewChangeEvent event) that would be normally triggered if I use the Navigator to change the view.
However, then I use a tab to change the content, there is no ViewChangeEvent fired.
How can I though trigger the enter() method of the specific view content of the tab?
#VaadinComponent
#UIScope
public class MyView extends CssLayout implements View {
private Label label;
public MyView() {
label = new Label("empty");
}
#Override
public void enter(ViewChangeEvent event) {
label.setValue("entered");
}
}
#VaadinComponent
#UIScope
public class MyMenu extends CssLayout {
private TabSheet tabs;
public MyMenu() {
tabs = new TabSheet();
addComponent(tabs);
}
#Autowired
private MyView myview;
#PostConstruct
public void init() {
tabs.addComponent(myview);
//some more tabs
}
}
You can use a Shortcut Listener like that
component.addShortcutListener(new ShortcutListener("caption", KeyCode.ENTER, null) {
private static final long serialVersionUID = 1L;
#Override
public void handleAction(Object sender, Object target) {
label.setValue("entered");
}
});
Related
I have this code for a login view:
#SuppressWarnings("serial")
#Route(AppConst.LOGIN_PAGE)
#PageTitle("Login")
#Viewport(AppConst.VIEWPORT)
public final class LoginView extends LoginOverlay
implements BeforeEnterObserver, ComponentEventListener<AbstractLogin.LoginEvent>{
public LoginView() {
LoginI18n i18n = LoginI18n.createDefault();
i18n.setHeader(new LoginI18n.Header());
i18n.getHeader().setTitle("App");
i18n.getHeader().setDescription("");
i18n.setAdditionalInformation(null);
i18n.setForm(new LoginI18n.Form());
i18n.getForm().setSubmit("Sign in");
i18n.getForm().setTitle("Sign in");
i18n.getForm().setUsername("Email");
i18n.getForm().setPassword("Password");
setI18n(i18n);
setForgotPasswordButtonVisible(false);
addLoginListener(this);
}
#Override
protected void onAttach(AttachEvent attachEvent) {
System.out.println("on attach called");
}
#Override
public void onComponentEvent(LoginEvent event) {
// do something
}
#Override
public void beforeEnter(BeforeEnterEvent event) {
setOpened(true);
}
}
When I run it the onAttach() method is called twice, I read on attach called two times on output.
The view is instantiated from another view via a beforeEnter(BeforeEnterEvent event) using event.forwardTo(LoginView.class).
Why ? is this a bug?
Thanks for the help.
I'm trying to create a generic/base form regardless if it is an activity or fragment. To make it simple, a Form can submit so:
class BaseFormActivity extends AppCompatActivity {
public abstract void submitForm();
#Override
public void setContentView(int layoutResID) {
ConstraintLayout activityBaseForm = (ConstraintLayout) getLayoutInflater().inflate(R.layout.activity_base_form, null);
FrameLayout frameBaseForm = activityBaseForm.findViewById(R.id.frame_base_form);
getLayoutInflater().inflate(layoutResID, frameBaseForm, true);
findViewById(R.id.btn_submit).setOnClickListener(v -> submitForm()) // for the sake of simplicity, there's a button that will trigger submitForm() method
super.setContentView(activityBaseForm);
}
}
Here, I just include some default layout for a form, and a button for submit that triggers the abstract method submitForm(). But, this is only for android activities. How can I make this also available for fragments without writing a BaseFormFragment? I don't want to repeat default behaviors from activity to the fragment and vice versa.
Consider it as a sample Presenter class which handle your button click and get all form fields and send to server
public class MyPresenter {
private MyPresenterIView iViewInstance;
public MyPresenter(MyPresenterIView iView){
this.iViewInstance=iView;
}
public void onSubmitClick(){
//write your logic here
String fieldOneText=iViewInstance.getFieldOneText();
sendToServer(fieldOneText);
}
private void sendToServer(String stringInfo){
//send info to server
}
}
MyPresenterIView Interface
public interface MyPresenterIView{
String getFieldOneText();
}
And use Presenter in your Activity or Fragment
//implement MyPresenterIView to your Activity or Fragment
public class MyActivity extent SomeActivity implements MyPresenterIView{
private MyPresenter myPresenter;
//in onCreate or onCreateView(if its a fragment) initialize myPresenter
protected void onCreate(..){
myPresenter=new MyPresenter(this);//this will enforce Activity/Fragment to implement IView
}
#Override //comes from MyPresenterIView
public String getFieldOneText(){
return ((EditText)findViewById(R.id.edttext_field_one)).getText().toString().trim();
}
}
I try to make java small project with intro and after full video or keypressed skip to menu. I made enums for state of "game". How i can switch JPanels and stop everything that old one is doing, because intro is also playing music in Thread.
contentPane.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
System.out.println("Clicked");
State = GameState.MainMenu;
}
});
if (State == GameState.Intro) {
contentPane.removeAll();
contentPane.add(intro);
contentPane.revalidate();
contentPane.repaint();
intro.music.interrupt();
System.out.println(State);
} else if (State == GameState.MainMenu) {
contentPane.removeAll();
contentPane.add(menu);
contentPane.revalidate();
contentPane.repaint();
System.out.println(State);
}
}
The first thing I would recommend is, making use of a CardLayout - See How to use CardLayout for more details.
It will make switching between the views much simpler.
Next, I would recommend devising some kind of "navigation" system which is independent of the views themselves. The idea is, any one view really should know or care which view is next (or previous) and should only be making "simple" requests to the navigation system, like "show next view". It's up to the navigation system to decide exactly what that means (and how to drive it).
This allows you more control over defining and managing the overall navigation process.
I would then couple that with a optional "life cycle" concept, which would allow the navigation system to notify those implementations when the navigation state was changing.
"How" you actually do this, will depend on a lot on your overall design and intentions, but it might look something like...
LifeCycle
public interface LifeCycle {
public void willShow();
public void didShow();
public void willHide();
public void didHide();
}
NavigationController
public interface NavigationController {
public void next();
}
public interface View {
public String getName();
public JComponent getView();
}
Default implementations...
public class DefaultView implements View {
private String name;
private JComponent view;
public DefaultView(String name, JComponent view) {
this.name = name;
this.view = view;
}
#Override
public String getName() {
return name;
}
#Override
public JComponent getView() {
return view;
}
}
public class DefaultNavigationController implements NavigationController {
private List<View> views;
private Container parent;
private CardLayout layout;
private View currentView;
public DefaultNavigationController(Container parent, CardLayout layout) {
this.parent = parent;
this.layout = layout;
}
protected Container getParent() {
return parent;
}
protected CardLayout getLayout() {
return layout;
}
public void add(String name, JComponent comp) {
getParent().add(comp, name);
views.add(new DefaultView(name, comp));
}
protected List<View> getViews() {
return views;
}
#Override
public void next() {
List<View> views = getViews();
if (views.isEmpty()) {
return;
}
int index = (currentView == null ? -1 : views.indexOf(currentView)) + 1;
if (index >= views.size()) {
// This is the last view
return;
}
View previousView = currentView;
View nextView = views.get(index);
willHide(previousView);
willShow(nextView);
getLayout().show(getParent(), nextView.getName());
didHide(previousView);
didShow(nextView);
currentView = nextView;
}
protected void willHide(View view) {
if (view != null && view.getView() instanceof LifeCycle) {
LifeCycle cycle = (LifeCycle)view.getView();
cycle.willHide();
}
}
protected void willShow(View view) {
if (view != null && view.getView() instanceof LifeCycle) {
LifeCycle cycle = (LifeCycle)view.getView();
cycle.willShow();
}
}
protected void didHide(View view) {
if (view != null && view.getView() instanceof LifeCycle) {
LifeCycle cycle = (LifeCycle)view.getView();
cycle.didHide();
}
}
protected void didShow(View view) {
if (view != null && view.getView() instanceof LifeCycle) {
LifeCycle cycle = (LifeCycle)view.getView();
cycle.didShow();
}
}
}
As you can see, I like working to interfaces, this hides the implementation details from other parts of the system and provides me with a better point of customisation. For example, components don't care "how" the NavigationController is implemented, only that it follows a specific and definable work flow.
Okay, but how might this work? Let's start with a basic implementation of a component that support LifeCycle, it might look something like...
public class IntroPane extends JPanel implements LifeCycle {
private NavigationController navigationController;
protected NavigationController getNavigationController() {
return navigationController;
}
protected void next() {
getNavigationController().next();
}
#Override
public void willShow() {
// Prepare any resources
// Lazy load resources
// Do other preparation work which doesn't need to be done in the
// constructor or which needs to be recreated because of actions
// in will/didHide
}
#Override
public void didShow() {
// Start animation loops and other "UI" related stuff
}
#Override
public void willHide() {
// Pause the animation loop and other "UI" related stuff
}
#Override
public void didHide() {
// Dispose of system intensive resources which can be recreated
// in willShow
}
}
And you might set it up using something like...
CardLayout cardLayout = new CardLayout();
JPanel contentPane = new JPanel(cardLayout);
DefaultNavigationController navigationController = new DefaultNavigationController(contentPane, cardLayout);
navigationController.add("intro", new IntroPane());
navigationController.add("menu", new MenuPane());
navigationController.add("game", new GamePane());
"But wait" you say, "this is a linear navigation, I need something more dynamic!"
Far point. In that case I would create, yes, another interface!! This would extend from the (linear) NavigationController and provide a means to "show" arbitrary named views.
Why do it this way? Because not all the views need the power to decide which view should be shown, some just want to show the next (or previous) view, for example, MenuPane might be the only view which actually needs a non-linear navigation controller, all the others just need to be able to move back or forward
But how do I stop a Thread
That's a complicated question, which isn't always easily answered. The "basic" answer is, you need to define a controlling mechanism which can work together with the "interruptable" support of the Thread and exit the thread context.
Maybe How to Kill a Java Thread would be a starting point
I created a dialog class:
myDailog extends Dialog
public myDailog (Shell parentShell, String tatgetEntity) {
super(parentShell)
}
#Override
protected Control createDialogArea(final Composite parent) {
final Composite body = (Composite) super.createDialogArea(parent);
...//some logic to create tableViewwer
}
The problem that I can't change the size of the dialog (stretch the windows).
Do I need to use different dialog?
Override the isResizable method of org.eclipse.jface.dialogs.Dialog:
#Override
protected boolean isResizable()
{
return true;
}
You may need to use this public method to enable the dialog to be resizable:
public void setResizable(boolean resizable)
ps I'm assuming you are using this java.awt.Dialog class
For example I want to execute something when user clicks on a button. Which do I use? The documentation didn't appear to make it very clear
UPDATE
A quick test shows that Widget Selected is triggered but not Default Selected.
In TasksView.main()
TasksView view = new TasksView(shell, SWT.None);
TasksController controller = new TasksController(view);
In TasksController
public class TasksController extends ControllerAbstract {
protected TasksView view;
public TasksController(TasksView view) {
this.view = view;
view.addTaskListener(new AddTaskListener());
}
protected class AddTaskListener implements SelectionListener {
#Override
public void widgetDefaultSelected(SelectionEvent arg0) {
System.out.println("Default Selected");
}
#Override
public void widgetSelected(SelectionEvent arg0) {
System.out.println("Widget Selected");
}
}
}
btw, Did I do MVC correctly?
Use widgetSelected. In fact, all the better is to simply extend SelectionAdapter and only override the widgetSelected method and completely ignore widgetDefaultSelected.
SelectionListener.widgetDefaultSelected(e) has a toolkit dependent behavior. I usually just invoke SelectionListener.widgetSelected(...). (Note that this is not the default in SelectionAdapter.widgetDefaultSelected(e) - you will have to do this yourself.