JavaFX Preventing TableMenuButton from hiding all columns - java

I want to use Table Menu Button (table.setTableMenuButtonVisible(true);) for hiding and showing specified columns in TableView. When I deselect all columns, [+] button hides, "No columns in table" pops in and user is unable to show any column.
I've tried to prevent hiding all columns by listening to table.getVisibleLeafColumns() and showing last hidden column, but then in ChoiceBox from Menu Button this column is unselected.

Definitely a bug (you might consider reporting it in fx' jira). The hack-around you mentioned in your question seems to work with a little trick borrowed from Swing: delay the reversion of visibility to some future:
ListChangeListener<? super TableColumn> visibleColumnsListener = c -> {
while (c.next()) {
// very last remove
if (c.wasRemoved() && !c.wasReplaced()) {
TableColumn column = c.getRemoved().get(0);
// delay reverting visibility
Platform.runLater(() -> {
column.setVisible(true);
});
}
}
};
It may be dirtier than its analogue in Swing, though, execution of the runnable is at "some unspecified time in future" and doesn't state its relation to normal (originating from the ui) events.
Reported as RT-38907 and just fixed (was duplicate: RT-37616), should bubble up in 8u40 ea in a week or two.

Related

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

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);
});

In CodenameOne, why is a checkbox not selected but appearing selected?

I Have an odd problem - not sure if there's a coding mistake or a bug in CN1.
Basically I create a row of CheckBox objects and put them in a container that is X-Scrollable. If i click on one un-selected item and drag until the "elastic" effect pulls it back, it appears to be selected, but the code does not record it as selected.
Please see the following video of the issue:
https://youtu.be/EtputE1kjyo
Note that in the Console output, the word 'selected' is capitalized when the field has been selected and lowercase when it is unselected. Same for focus (I added focus to the output to determine if setFocusable() was working as desired so that focus was not to blame for the selection error).
here's the Checkbox creation code:
cb = new CheckBox(getCacheableImageMaxHeight(mod.getIconFile(),moduleImageHeight));
cb.setName(mod.getModuleID());
cb.setToggle(true);
cb.setUIID("ModuleButton");
cb.setFocusable(false);
cb.setScrollVisible(false);
cb.setTextPosition(Component.BOTTOM);
cb.setCloudDestinationProperty(cb.getName());
//actionlistener added for debugging only
final CheckBox cbFinal = cb;
final String modName = mod.getDisplayName();
cb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println(modName+", "+(cbFinal.isSelected()?"SELECTED":"selected") + ", " + (cbFinal.hasFocus()?"FOCUS":"focus"));
}
});
c.addComponent(cb);
UPDATE: I've realized there are two "states" at war here:
The toggleButtons (I now realize they're not just CheckBoxes since I set "setToggle(true)) are getting stuck in the "pressed" state as they are dragged and released with the "elastic" effect. Unfortunately, the "pressed" and "selected" states have the same appearance so that means my users think they have selected something when it's just stuck being "pressed" during a drag operation.
Here's some more debugging I did.
The first button is Pressed, but not selected (the bug).
the second button is Selected normally and not showing the bug.
The Third button is interesting because I selected it, then dragged and released it to get it to be SELECTED and PRESSED!
So the question changes to: Is there an open bug for this situation already (Pressed state gets stuck on after button is released) and if so, is there a fix coming or a workaround for now?
Just style the selected state to look different from the pressed state and it should work fine.
In a touch device selected state isn't rendered when the finger is up. This is almost always true unless you changed a flag in Display or set some arcane theme constant.
So I figured out a more effective workaround that doesn't involve adding a separate pressed style (since there could be buttons selected, pressed, and selected+pressed with the bug)
I needed to capture the event that scrolling stopped and then check the state of the buttons to make sure none were still pressed. To do this, I used addPointerReleasedListener on the scrolling container to detect when the pointer came off (so its components are definitely no longer pressed), and then in its Runnable, I make sure each one is released.
scrollingContainer.addPointerReleasedListener(evt -> {
Container cont = (Container) evt.getComponent();
Iterator<Component> buttons = cont.iterator();
while (buttons.hasNext()){
Button button = (Button) buttons.next();
if (button.getState() == Button.STATE_PRESSED) {
button.released();
}
}
});
So far seems to solve the problem. Now we just need a permanent fix, or a note in the documentation of ToggleButtons that when they are in a scrolling container, they could get stuck in a pressed state and need to be released.

Start Editing a cell in JTable automaically

I am developing a restaurant billing system.
So here is the order panel interface
So now when i click on the menuTable the item code automatically gets added to kotTable
and when i press "Q" the focus shifts to quantity column in kotTable.
`
private void menuTableKeyTyped(java.awt.event.KeyEvent evt)
{
if(evt.getKeyChar()=='Q') {
kotTable.editCellAt(i-1,2);
}
} `
The problem is The cell doesnt start editing automatically. I need to click on that cell and then the editing starts.
i tried using DefaultCellEditor , getInputMap() and many other. But I am bit confused and the problem is not solved.. Thanx
Using a key binding, you can map the Q key to the table's "startEditing" action. More examples may be found here.
table.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0), "startEditing");

JTooltip in JTable on Mac in Java does not select the row when clicked on

On Windows if you click on the table tooltip (JToolTip), it will remove the tooltip AND select the row in the table. However on the Mac, it seems to just remove the tooltip and does NOT select the row in the table.
The code just uses a standard JTable and overrides getToolTipText method from JTable. No custom JToolTip is created or anything like that.
Code:
public class MyJTable extends JTable
{
#Override
public String getToolTipText(MouseEvent event)
{
return "Hello world";
}
}
**Update: On further investigation the issue seems to be due to something similar to this bug report. Basically the ToolTipManager.showTipWindow() is creating the tooltip as a HeavyWeight component on the Mac and a LightWeight component on Windows, which then causes the mouselistener not to be fired. The worse part is that regardless if you set the popupType to be lightweight, it will still create it as a heavyweight component in that method when the Java code calls popupFactory.getPopup(...)
No idea how to fix it.
Normally a different tooltip is given for each row or cell and not the entire table. So as you move the mouse the tooltip changes and is displayed in a different location so you never get an opportunity to actually click on the tooltip.
So, maybe as an alternative approach, you could also override the getToolTipLocation() method:
public Point getToolTipLocation(MouseEvent e)
{
return new Point(e.getX(), e.getY() + 10);
}
Now the user will never be able to click on it.
The reason clicking on the ToolTip does not generate a MouseEvent on the JTable is because the ToolTip is generated as a HEAVY_WEIGHT_POPUP rather than a LIGHT_WEIGHT_POPUP.
This can be due to a number of reasons, even something as simple as a L&F that does this.
The way it works in Java Swing is that the PopupFactory will create the ToolTip. In Java mixing HeavyWeight and LightWeight component can have some ramifications and as a result around Java 5-6 (not sure which) the Java language added the ability to define this property, however some L&F libraries don't use it or correctly adhere to it. And if you're using an older version it may just not be possible. For more details on the need for this toggle you can read the following bug report before the toggle was added to Swing.
In any case, if the component (in this case the ToolTip) is a HEAVY_WEIGHT_POPUP then the MouseEvent will not propagate to the JTable, and hence only the ToolTip will disappear and the row in the table will not be selected. The ToolTip needs to be a LIGHT_WEIGHT_POPUP for the MouseEvent to propagate to the JTable.

Making a JTable cell editable - but *not* by double clicking

I am trying to add a column to a JTable with the following behaviour (similar to Windows Explorer and similar shells):
The cell can be clicked once to select it, as usual.
The cell can be double-clicked to perform a separate action (launching an external program.)
The cell value (a string) can still be edited, by single-clicking a second time (after a pause) or by pressing F2 when the cell is highlighted.
Double-clicking must not trigger editing of the cell, but I would like to leave any other default editing triggers operational if possible.
I have tried adding a MouseListener to the table, and consuming all MouseEvents, but this does not work - if I return true from isCellEditable() then my listener never receives any click events but if I return false then F2 no longer works.
Can this be achieved using only event listeners? I would prefer not to mess with the PLAF functions if I can avoid it.
The DefaultCellEditor has a setClickCountToStart() method to control mouse clicks for editing. The default is 2. Changing this will have no effect on F2 functionality.
Therefore you can set editing to be a triple click.
Not sure exactly how to handle two single clicks to start editing but I guess you would use a Timer to keep track of the first click and then do the editing if the second single click is within you time interval.
You will have to make your own cellEditor and ovveride
public boolean isCellEditable( EventObject e )
You can distinguish between single and double click with the clickCount on the eventObject
If its a single Click and its on a selected cell you can return true otherwise return false;
retrieve row and column with
int row = ( (JTable) e.getSource() ).rowAtPoint(e.getPoint());
int column = ( (JTable) e.getSource() ).columnAtPoint(e.getPoint());
to enable F2 you can add custom inputMap en actionMap entries
similar too
table.getInputMap().put(KeyStroke.getKeyStroke("DOWN"), "doMyArrowDown");
table.getTable().getActionMap().put("doMyArrowDown", new ArrowDownAction());
and from your action you can then fire the cellediting yourself
table.editCellAt(row, column );
I have solved this by wrapping the existing CellEditor with a Proxy and intercepting calls to isCellEditable, returning false for all mouse events and delegating all other calls to the original CellEditor.
This is slightly more complex than camickr's solution but works for all editors (I have 4 in all.)

Categories