Need to trigger JavaFX TableView's built-in Table Menu Button - java

I have an application where a TableView will be created dynamically based on a database query. This means that my application will have multiple tables with differing columns.
I must display a separate button to show/hide columns. I am familiar with the table menu button triggered with table.setTableMenuButtonVisible(). Unfortunately, I cannot use the actual on-screen built-in button on the UI, although I would like to use it's functionality.
I am essentially looking for a table.getTableMenu().show()
sort of call. But I can't find where this is a built in method of any sort. Is there a way that I can call this button's action from a UI button of my own design?

Actually, I was wrong in my comment: it is possible to lookup the corner region and trigger its mousePressedHandler without reflection.
The following code snippet opens the corner menu just as if it had been clicked directly (in fx11 at least, and still dirty in relying on the implementation detail that opening is triggered by a mousePressed event):
Button showCorner = new Button("open menu button");
showCorner.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
Node corner = table.lookup(".show-hide-columns-button");
corner.fireEvent(e);
});

Related

CaptainCasa framework: DOF reactOnInstanceSelect conflicting with clickable items in the grid

In a few DOF grids I have icons and buttons with click actions added using a DOF extension. I also want to trigger another action when single-clicking on a grid row (reactOnInstanceSelect). I want to avoid triggering the reactOnInstanceSelect action when clicking on the icons/buttons.
Right now when I click on a button, both the button event and the reactOnInstanceSelect event are fired. The event sequence seems to be random. (in my case both events opened a popup, and the resulting popup sequence is random, the event fire sequence is not)
There is a function...
List<FacesEvent> requestEvents = ThreadData.getInstance().getRequestEvents();
...which gives you all events that are contained in a roundtrip. Could you try this one to find out in the "reactOnInstanceSelect" if another event occurs in parallel?
By the way: the event sequence is driven by the sequence of components in the component hierarchy.

Refresh grid from another UI in Vaadin

I have a main Layout that contains another UI with grid and a button. This grid shows the data of a table of my database. With the button a wizard gets open, where i can create a new entry to this database. When i close the wizard with a button click, i want the grid to refresh in order to show also the newly added entry. Everythin works fine, including the storage to my database, except the refresh of my grid.
So i have the UI
public class MainLayout{
...
public void refreshGrid()
{
this.grid.getDataProvider().refreshAll();
}
}
where my grid is defined. I already implemented the refresh method.In there is also the button to create a new entry. When i click this button the next UI gets called.
This UI contains the general layout of the wizard, with a tab bar.
public class WizardLayout{
}
In one of those tabs there is finally the UI with the input fields to create the entry. There is also the button to save it to the database.
public class CreateEntry{
...
private void button_onClick(ClickEvent<Button> event)
{
...
}
}
In this button click method the logic is implemented to save it. And after that i would like to call the refresh method from the first UI in order to refresh it. How do i do that, so that it works?
Please remember, everything else works. So my only problem is to refresh the grid because it does not automatically. I have to click the refresh button in my browser to make it work.
First note that while not incorrect, your use of the term UI might be confusing in a Vaadin context, as it's usually used to refer to Vaadin UI objects, of which there is generally one per tab. Communication between Vaadin UIs is more complex than your use case.
There are plenty of solutions for this, the easiest is probably to pass an instance of your MainLayout to your wizard.
In that case, the classes will be tightly coupled, i.e. both depend on each other.
A better way is with some kind of listener or callback. This can be made quite complex, but in the easiest case you just pass a callback that will be run on save.
WizardLayout.java
private final Runnable saveCallback;
public WizardLayout(Runnable saveCallback) {
this.saveCallback = saveCallback;
}
private void button_onClick(ClickEvent<Button> event) {
...
saveCallback.run();
}
MainLayout.java
new WizardLayout(this::refreshGrid);
Is your dataprovider using in-memory items, or do you use a callback dataprovider with lazy loading?
You are probably using an in-memory dataprovider. This is the case, when you load your items from the database and put them in the grid with
grid.setItems(fooService.findAll());
Calling grid.getDataProvider().refresh() will only refresh the items that are already set. Since you have a new item to display, you have to fetch all items again from the DB with your service.
grid.setItems(fooService.findAll());
grid.getDataProvider().refreshAll();
If you're using a callback dataprovider with lazy loading, then I think just refreshing the dataprovider should be enough. I don't know enough about lazy loaded dataproviders to provide a solution to this issue but I do believe this issue should not arise in the first place if using a callback dataprovider

Using SWT for multi-view application; similar to Android activity lifecycle

So my situation is simple (IMHO):
I am trying to create web-esque Java application (it's a sort of Point-Of-Sale application) that behaves much like a website, but is all in Java. Right now I have a semi-simple SWT application written in Eclipse and it displays a few options (sign in, price check, inventory check and employee timeclock). When any of these is pressed (or corresponding keyboard shortcuts are activated) a dialog box pops up prompting authentication. Assuming user is verified, I want the main application window to display a new set of functions (scan item, item lookup, etc.) seamlessly.
If this were HTML I would just make a new page, and if I were writing against the Android platform I would just create a new activity...but this is very new and I am having a very hard time finding any relevant information.
PS I'm not set on SWT if anybody thinks a different library/technology (such as Swing/AWT) is better.
In SWT, if you want to replace the content of a Composite, you first need to dispose the existing controls, next you create the new controls, and finally call the layout(...) method on the Composite:
// Retrieve existing composite
Composite composite = [retrieve existing composite]
// Remove exising children
for (Control child : composite.getChildren()) {
child.dispose();
}
// Create new children
Label label = new Label(composite, SWT.NONE);
// Layout
// Maybe update the composite layout with composite.setLayout()
composite.layout(true, true);
Another solution is to use a Composite with a StackLayout if you want to display back and forth several predefined contents.
Whether you use Swing, AWT or SWT is entirely your choice. Personally, I prefer Swing, but you can do the same thing with SWT.
As for your predicament, you need to do a bit of studying regarding GUI's first. A Java desktop application consists of a top-level container, usually a JFrame (Window) that can contain other components, windows, dialog boxes etc. Your best best here is to pop up a MODAL dialog box that asks the user for authentication information. If the user is authenticated, you can dynamically create buttons, text boxes etc. in your code, creating the "new" look you want.
Might I suggest you start of with some simple GUI design exercises first, before diving into a full-fledged application? Consider the Java GUI tutorials at http://docs.oracle.com/javase/tutorial/uiswing/ as a good starting point.
Once you have mastered basic dialogue boxes, forms and components, you'd be in a far better position to plan your GUI and will find it easier to create it just the way you want it.

Passing accelerator keystrokes to the main menu in Java

I have added some accelerators to the main menu, using MenuItem.setAccelerator(). Just basic stuff like ctrl-c for copy, etc.
This works ok. But the app is a bit like an IDE, it has several panels containing JTables. If a table cell has focus, it absorbs the accelerator key, which means the main menu never sees it.
Clearly, if an editable table cell is active I would like the cut and paste keys to function normally, but in every other case I would like the main menu to respond.
Any ideas?
KeyStrokes go to the component that has focus first. Since JTable binds Ctrl+C to an Action, that action is invoked.
If you don't like the default Action of the table, then you would need to remove the binding from the table.
Read the section from the Swing tutorial on How to Use Key Bindings. It shows you how to remove a binding.
Thanks, that got me on the right track.
Removing the bindings didn't quite work, it just stopped the table doing its default action so the keypress was ignored altogether.
However, adding this to the table itself worked ok:
component.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK), "copy");
component.getActionMap().put("copy", actions.copyAction);
(Repeated for each desired key of course). Needs to be kept in synch with any changes to the main menu itself, but I can't see a way to avoid that with any method.

Can multiple accelerators be defined for a JMenuItem?

I've a problem with setAccelerator(). Right now, I have the code that works for Ctrl+X for DELETE operation. I want to set the accelerator to Shift+Delete as well for same JMenuItem.
My code as follows:
JMenuItem item = new JMenuItem(menuText);
item.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_X, KeyEvent.CTRL_MASK));
item.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_DELETE, KeyEvent.SHIFT_MASK));
but this is working only for Shift+Delete operation. Seems it is overriding the Ctrl+X operation. Can we make both these keystrokes work at the same time?
Please guide.
Yes it can be done. Behind the scenes the setAccelerator() is just creating a Key Binding, however as you noticed the second binding replaces the first.
So, you need to create an Action (not an ActionListener) to add the to the menu item. Read the section from the Swing tutorial on How to Use Actions for more information. Now that you have created the Action, you can share the Action with another KeyStroke by manually creating a Key Binding. You can read the section from the Swing tutorial on How to Use Key Bindings for a detailed explanation. Or you can read my blog on Key Bindings which give some simple code examples.
This second binding will not show up on the menu item itself.
From: http://java.sun.com/j2se/1.4.2/docs/api/java/awt/AWTEvent.html
The masks are also used to specify to which types of events an AWTEventListener should listen.
So you can combine the mask for two keys, but not the KeyEvents.
item.setAccelerator(
KeyStroke.getKeyStroke(
KeyEvent.VK_X, KeyEvent.CTRL_MASK + KeyEvent.SHIFT_MASK));
A workaround solution would be to catch the KeyEvent in the middle (after your component fired it, but before your listeners will act on it) and check, whether its one of the two combinations. Then fire one event, on which you programmatically agree to represent the action you wanted.
The second call indeed overrides the accelerator. If the method starts with set, there will be only one. If the method starts with add, you can have more than one (for example for a number of listeners).
If you want multiple keystrokes to do the same, I think you should add a keyListener to the top frame (or panel, dialog, ...) which invokes the action listeners added to the menuItem.

Categories