Menu accelerator SWT.ALT+SWT.ARROW is not triggered - java

I'm using SWT 4.4.2 (win32) to build the Graphical User Interface for a simple mp3 player application.
In a SWT tree I show some folders and files to play.
Now I want to change the volume of a playing file by clicking a menu item and also by pressing ALT+ARROW_UP and ALT+ARROW_DOWN.
So I have these components:
tree = new Tree(shell, SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE | SWT.V_SCROLL);
tree.setLinesVisible(true);
tree.setLocation(10, 10);
tree.setSize(240, 440);
audioLouderMenu = new MenuItem(audioVolumeMenu, SWT.PUSH);
audioLouderMenu.setAccelerator(SWT.ALT | SWT.ARROW_UP);
audioLouderMenu.setText("Louder");
audioLouderMenu.addListener(SWT.Selection, audioVolumeMenuHandler);
audioQuieterMenu = new MenuItem(audioVolumeMenu, SWT.PUSH);
audioQuieterMenu.setAccelerator(SWT.ALT | SWT.ARROW_DOWN);
audioQuieterMenu.setText("Quieter");
audioQuieterMenu.addListener(SWT.Selection, audioVolumeMenuHandler);
The problem is that if the tree view has the focus and I press ALT+ARROW_DOWN then another entry in the tree will be selected and not the shortcut of the menu item is triggered.
Is this a bug of SWT and how can I solve the problem?
I know that I can define another shortcut but I think that it should also be possible to use ALT+ARROW_UP/DOWN...

This isn't a bug but a (platform-dependant) keyboard navigation feature of the tree.
I recommend to choose a different shortcut for the audio volume in order to not confuse your users. If you nonetheless want to use ALT+ARROW_DOWN, you can try to prevent the tree from consuming this key combination and thus give the menu a chance to consume it:
tree.addListener( SWT.KeyDown, new Listener() {
#Override
public void handleEvent( Event event ) {
if( event.keyCode == SWT.ARROW_DOWN && ( event.stateMask & SWT.MOD3 ) != 0 ) {
event.doit = false;
}
}
} );

Related

Add SWT widget Group when a checkbox is selected

I have a GUI which has 3 different sections. In one of the section I have 2 checkboxes.
I want to add one more widget multiple selection List when one of the checkbox is selected.
I added a selectionListener to checkbox and when it is selected I am calling method which creates multiple selection List.
Problem is this list is not getting added in the GUI when checkbox is selected and it is not removed when checkbox is unchecked.
I am not able to find the cause. Can anybody help me?
Below is the code to add the multiple selection list
private void createFirstLevelSubFolderGroup() {
GridData gridData = new GridData();
gridData.grabExcessVerticalSpace = true;
gridData.verticalAlignment = org.eclipse.swt.layout.GridData.FILL;
gridData.horizontalAlignment = org.eclipse.swt.layout.GridData.FILL;
gridData.grabExcessHorizontalSpace = true;
subFolderGroup = new Group(this, SWT.NONE);
subFolderGroup.setLayout(new FillLayout());
subFolderGroup.setLayoutData(gridData);
subFolderGroup.setText("First Level SubFolder");
firstLevelFolderList = new List(subFolderGroup, SWT.V_SCROLL | SWT.MULTI);
subFolderGroup.setVisible(true);
//firstLevelFolderList.setVisible(false);
}
//code where the call to add this list is there
//code adding a checkbox is here and below am adding a listener to that checkbox
ArchiveCheckbox.addSelectionListener(new SelectionAdapter()
{
#Override
public void widgetSelected(SelectionEvent e)
{
if (ArchiveCheckbox.getSelection()) {
// here am trying to call the method which adds multiple selection list
createFirstLevelSubFolderGroup();
}
else {
// I want to remove that widget
subFolderGroup.setVisible(false);
firstLevelFolderList.removeAll();
}
}
}
Basically I am not able to add this dynamically.
A small code snippet which demonstrates my scenario is fine if the code which I provided doesn't have the req info.
![Below is the gui which I am creating. When check box prepare archive for catch is selected I want a multiple selection list should appear just below the checkbox and it should disappear when it is unchecked. Currently when it is checked multiple selection list appearing but it hides the other group Model that contains sources ][1]
[2]: http://i.stack.imgur.com/Xl2ml.png
Create all the controls at the start. Set a GridData layout on each control you want to hide and set the exclude flag to true and make in control invisible. So something like:
Control control = .. create control ...
GridData data = new GridData(flags);
data.exclude = true;
control.setLayoutData(data);
control.setVisible(false);
When you want to make the controls visible set the exclude flag to false, make the control visible and call layout() on the parent Composite.
GridData data = (GridData)control.getLayoutData();
data.exclude = false;
control.setVisible(true);
parentComposite.layout();

Trying to add a menu to a TableViewer's header row (titles row)

I am trying to add an action to a menu to the header (titles) of a TableViewer.
This is the code that I am using now:
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL
| SWT.FULL_SELECTION | SWT.BORDER);
//...
MenuManager manager = new MenuManager();
viewer.getControl().setMenu(manager.createContextMenu(viewer.getControl()));
manager.add(new Action("MENU ITEM TEXT") {
#Override
public void run() {
// get the current selection of the tableviewer
IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
// do something
if (selection.getFirstElement() instanceof MyObject)
return;
System.out.println("OK: "+selection.getFirstElement().getClass().getName());
}
});
And this is how it looks:
The problem is that the menu gets added to the entire TableViewer, not only to the header row.
Because for the other rows I will need to use a different menu.
I have tryied to find a way of adding the action only to the top row (the titles row), but with no success so far.
So how can I add the menu only for the header?
You add a MouseListener to the table, and you check for the following things:
Clicked button is mouse right-click.
The pointer of the event is located within the bounds of your table item (i.e. your first TableItem - you will use table.getItem(Point)).
If these conditions are met, you open the menu at mouse location.
Actually, here's a snippet of how this can be done.

How to bind command-? as a swing action accelerator for a help menu?

The standard key combination for help is command-? on macs. How can I bind this key combination to a menu item.
Note: As our users have different keyboard layouts I´m looking for a solution that does not require knowledge about what key "?" is located on.
Using KeyStroke.getKeyStroke(String), which javadoc says;
Parses a string and returns a `KeyStroke`. The string must have the following syntax:
<modifiers>* (<typedID> | <pressedReleasedID>)
modifiers := shift | control | ctrl | meta | alt | button1 | button2 | button3
typedID := typed <typedKey>
typedKey := string of length 1 giving Unicode character.
pressedReleasedID := (pressed | released) key
key := KeyEvent key code name, i.e. the name following "VK_".
I have this example code:
import javax.swing.*;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
public class HelpShortcut extends JFrame {
public HelpShortcut(){
// A few keystrokes to experiment with
//KeyStroke keyStroke = KeyStroke.getKeyStroke("pressed A"); // A simple reference - Works
//KeyStroke keyStroke = KeyStroke.getKeyStroke("typed ?"); // Works
KeyStroke keyStroke = KeyStroke.getKeyStroke("meta typed ?"); // What we want - Does not work
// If we provide an invalid keystroke we get a null back - fail fast
if (keyStroke==null) throw new RuntimeException("Invalid keystroke");
// Create a simple menuItem linked to our action with the keystroke as accelerator
JMenuItem helpMenuItem = new JMenuItem(new HelpAction());
helpMenuItem.setAccelerator(keyStroke);
// Install the menubar with a help menu
JMenuBar mainMenu = new JMenuBar();
JMenu helpMenu = new JMenu("Help");
helpMenu.add(helpMenuItem);
mainMenu.add(helpMenu);
setJMenuBar(mainMenu);
}
// Scaffolding
public static void main(String[] pArgs) {
HelpShortcut helpShortcut= new HelpShortcut();
helpShortcut.setLocationRelativeTo(null);
helpShortcut.setSize(new Dimension(100, 162));
helpShortcut.setVisible(true);
}
private class HelpAction extends AbstractAction {
public HelpAction() {
putValue(Action.NAME,"Help me!");
}
#Override
public void actionPerformed(final ActionEvent pActionEvent) {
JOptionPane.showMessageDialog(HelpShortcut.this,"You should ask StackOverflow!");
}
}
}
On my keyboard the "?" is above the "/" key so you also next to use the shift key to type the "?". So to do the binding you need to use:
// KeyStroke keyStroke = KeyStroke.getKeyStroke("meta typed ?");
int modifier = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
+ KeyEvent.SHIFT_DOWN_MASK;
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, modifier);
See KeyEvent API doc - notes section:
Not all characters have a keycode associated with them. For example, there is no keycode for the question mark because there is no keyboard for which it appears on the primary layer.
(surprisingly - to me :-) modifiers to bindings of keyIDs "typed" are not supported: while you can create and bind such into the inputMap, they are never found because keyStrokes internally generated for typed keyEvents do use the keyChar and ignore the modifiers. That creation happens in JComponent.processKeyBindings(...)
boolean processKeyBindings(KeyEvent e, boolean pressed) {
if (!SwingUtilities.isValidKeyEventForKeyBindings(e)) {
return false;
}
// Get the KeyStroke
KeyStroke ks;
if (e.getID() == KeyEvent.KEY_TYPED) {
ks = KeyStroke.getKeyStroke(e.getKeyChar());
}
else {
ks = KeyStroke.getKeyStroke(e.getKeyCode(),e.getModifiers(),
(pressed ? false:true));
}
Thinking about it, that may make sense: pressed/released handles the physical keys, while typed is the final combined "output" of one or more physical keys. If there is no valid keyChar for any given combination, there is no keyTyped event generated.
The base problem is the well-known usa centrism of the swing/awt developers: they counted as physical keys only those on the us layout ;-) No way (that I know of) to get at other keys in a layout-agnostic manner. Hope to be proven wrong

SWT: Table with copy/paste functions

This maybe a really silly question but I just could not find the answer anywhere, is there any way for the user to be able to highlight rows in an SWT Table and either ctrl+c or right-click+c to copy the values?
I would specifically like to be able to copy into an excel sheet.
This is how I create the table,
Table aTable = new Table(parent, SWT.SINGLE | SWT.BORDER
| SWT.FULL_SELECTION);
aTable.setHeaderVisible(true);
aTable.setLinesVisible(true);
aTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
I have seen information about this using a JTable but nothing with an SWT. If JTable is my only option, then what would be the dis/advantages of using either?
You can easily code it.
Add a key listener to your table and listen for Ctrl+C keys. When Ctrl+C is hit, get the selection from the table, extract text from each of the TableItems and form a tab-separated-fields/newline-separated-rows String containing your data. Then just put it into clipboard (see org.eclipse.swt.dnd.Clipboard#setContents, use TextTransfer data type).
That is it - your result will be pasteable into Excel.
The accepted answer is good, but since developers prefer code snippets over text I'd answer the question this way:
aTable.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.stateMask == SWT.CTRL && (e.keyCode == 'c' || e.keyCode == 'C')) {
Clipboard clipboard = new Clipboard(Display.getDefault());
clipboard.setContents(new Object[] { getTextFromSelectedRows() }, new Transfer[] { TextTransfer.getInstance() });
clipboard.dispose();
}
}
});
Then just implement a getTextFromSelectedRows()-Method that - based on the table selection - returns the String that should be added to the clipboard.

How Do You change A ScrolledComposite's Horizontal Scroll Increment?

I have an application that displays a ScrolledComposite. Users are complaining that the horizontal scrolling increment is too fine, i.e. each click on the horizontal scroll arrow currently moves the bar one pixel at a time. They want individual clicks to cause greater horizontal movement. Could someone explain how I could implement this? A snippet of the code follows:
ScrolledComposite myScrolledComposite = new ScrolledComposite(parent,
SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
if ( myScrolledComposite == null) {
throw new NullPointerException("ScenePreView.java: " +
"Method createPartControl() " +
"ScrolledComposite myScrolledComposite == null.");
}
Composite myComposite = new Composite(myScrolledComposite, SWT.NONE);
if ( myComposite == null) {
throw new NullPointerException("ScenePreView.java: " +
"Method createPartControl() " +
"Composite myComposite == null.");
}
myScrolledComposite.setContent(myComposite);
This should work pretty well and provide usable defaults. It should update automatically when the control inside the ScrolledComposite is resized.
myComposite.addControlListener( new ControlAdapter() {
#Override
public void controlResized( ControlEvent e ) {
ScrollBar sbX = scrolledComposite.getHorizontalBar();
if ( sbX != null ) {
sbX.setPageIncrement( sbX.getThumb() );
sbX.setIncrement( Math.max( 1, sbX.getThumb() / 5 ) );
}
}
});
Get the scrollbar from the composite and set it's increment.
myScrolledComposite.getVerticalBar().setIncrement(10);
Use the setIncrement() method of the SWT Scrollbar class. This lets you modify the amount by which the scroll region moves when the arrow buttons are pressed.
See API Reference for SWT
I know it's more than you asked for, but I highly recommend checking out the SWT animation toolkit which has an implementation of smooth scrolling. It will make your application way cooler.
You can check it out and see the sources - it's a good example (yet, a bit advanced) of how to play with the scrolling.

Categories

Resources