keyboard vs menu conflict on Java 7, Mac OS - macos

How can I get a Java 7 application to have its menu bar at the top of the screen (on a Mac) and also have correctly working keyboard shortcuts?
I have a Java application with a Swing user interface. Many menus have keyboard equivalents, which are essential.
There is very little that is system-dependent, but on Mac OS X the menu bar should appear at the top of the screen instead of on each window, so I set apple.laf.useScreenMenuBar.
This works fine on Java 6, but on Java 7 (out last week!) compiling and running the same code causes the keyboard shortcuts to carry out their menu actions twice. For example, in the attached code, Command ⌘ + O opens two file dialogues instead of one. (The other keyboard shortcuts also act twice, but you sometimes have to move windows to see that they did.)
The keyboard problem goes away if I don't set apple.laf.useScreenMenuBar, and that's what I'll do if I have to, but my Mac users will be displeased. I'd really like to have the menu bar in the right place and the keyboard shortcuts working.
System: Mac OS 10.7.3 (Lion) on a late-2010 MacBook Pro
Java 7:
java version "1.7.0_04"
Java(TM) SE Runtime Environment (build 1.7.0_04-b21)
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)
Java 6:
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b04-415-11M3635)
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01-415, mixed mode)
Where I've looked:
A discussion of why apple.laf.useScreenMenuBar should be gotten rid of
-- I'm all for it, but it doesn't seem to have happened.
A discussion about not using mrj.version to detect that you're on a Mac
-- not directly relevant, but sounded promising.
My apologies for the length of the attached code (148 lines), but my Swing coding is very old-fashioned. It should compile and run from the command line without any special flags or settings.
import javax.swing.*;
import java.awt.Toolkit;
import java.awt.*;
import java.awt.event.*;
/**
* Shows that using the single screen-top menu bar on a Mac with Java 7
* causes keyboard shortcuts to act twice.
*
* To see the problem(on a Mac -- running OS X 10.7.3 in my case):
* 1) compile on either Java 6 or Java 7
* 2) run on Java 7
* 3) give the command-O shortcut
* You will see two file dialogues.
*
* -- J. Clarke, May 2012
*/
public class MenuBug {
private static void go(String[] args) {
// Comment out the following line to fix the problem;
// leave it active to see the problem.
// It doesn't help to ...
// ... put the line into a static block.
// ... put the line right after the setLookAndFeel call.
// ... put the line before after the setLookAndFeel call.
System.setProperty("apple.laf.useScreenMenuBar", "true");
MainWindow mainWindow = new MainWindow();
}
public static void main(final String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {
JOptionPane.showMessageDialog(null,
e + " while loading look and feel",
"MenuBug error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
go(args);
}
});
}
}
class MainWindow extends JFrame {
MainWindow() {
super ("Main Window");
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener (new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
});
JMenuBar menuBar = createMenuBar();
setJMenuBar(menuBar);
pack();
setSize(350,300);
setVisible(true);
}
private JMenuBar createMenuBar() {
JMenuBar mBar = new JMenuBar();
JMenu menu = new JMenu("File");
String[] menuItemNames = new String[] {"New", "Open...", "Other"};
for (int i = 0; i < menuItemNames.length; i++) {
String miName = menuItemNames[i];
JMenuItem mi = new JMenuItem(miName);
mi.setActionCommand(miName);
linkMenuItemToAction(mi);
menu.add(mi);
}
mBar.add(menu);
return mBar;
}
/**
* Create an Action for menuItem, and make sure the action and the menu
* item know about each other; where appropriate, add keyboard equivalents.
* #param menuItem The menu item to be linked to an action.
*/
private void linkMenuItemToAction(JMenuItem menuItem) {
final int META_MASK =
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
Action a = null;
String miName = menuItem.getActionCommand();
if (miName.equals ("New")) {
a = new NewAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
META_MASK));
}
else if (miName.equals ("Open...")) {
a = new OpenAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
META_MASK));
}
else if (miName.equals ("Other")) {
a = new OtherAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T,
META_MASK));
}
menuItem.setEnabled(a.isEnabled());
menuItem.addActionListener(a);
}
private class NewAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
new MainWindow();
}
}
private void makeDialog() {
String dialogTitle = "Please choose a file to open";
FileDialog fileDialog = new FileDialog(this, dialogTitle,
FileDialog.LOAD);
fileDialog.setVisible(true);
String fileName = fileDialog.getFile();
}
private class OpenAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
makeDialog();
}
}
private class OtherAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null,
"an example message",
"not really an error", JOptionPane.ERROR_MESSAGE);
}
}
}

I'm answering my own question -- sort of. As noted in the comments to the original, the trouble goes away with Java 1.7u10.

It looks like that this problem still exist but now it can be reproduced with fn + backSpace (delete) on mac with 1.7_21.
I used the same example as above just added text field. Select part of text in textfield and press delete (fn+backspace)
Change KeyStroke to "DELETE" in linkMenuItemToAction method
else if (miName.equals ("Other"))
{
a = new OtherAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke("DELETE"));
}
and add this:
JTextField textField = new JTextField(10);
textField.setText("Long long long long long long long text");
add(textField, BorderLayout.PAGE_START);
to MainWindow constructor.

Related

Permanently hide the Task List window in Visual Studio 2017

I haven't been able to find an answer for this online, but basically I want to permanently hide the Task List window that pops up whenever I test a Biztalk map. Right now I've found a temp solution by minimizing the window as much as possible, so it doesnt get in the way, but it would be nice to get rid of it entirely.
This is the window in question.
Unfortunately, no (for clarity, the answer is no...unless you want to write an Shell Extension ;).
I'm often as frustrated by this as you but have found that simply tucking it away in a corner or along the status bar is just as good as hiding it.
I presume the activate action is baked into the map designer.
You can try the following extension for Visual Commander to automatically close the Task List window once it is displayed:
public class E : VisualCommanderExt.IExtension
{
public void SetSite(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package)
{
events = DTE.Events;
windowEvents = events.WindowEvents;
windowEvents.WindowActivated += OnWindowActivated;
}
public void Close()
{
windowEvents.WindowActivated -= OnWindowActivated;
}
private void OnWindowActivated(EnvDTE.Window gotFocus, EnvDTE.Window lostFocus)
{
try
{
if (gotFocus.Caption == "Task List")
CloseWindow(gotFocus);
}
catch (System.Exception)
{
}
}
private void CloseWindow(EnvDTE.Window w)
{
System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Background,
new System.Action(() =>
{
try
{
w.Close();
}
catch (System.Exception)
{
}
}
));
}
private EnvDTE.Events events;
private EnvDTE.WindowEvents windowEvents;
}

JavaFX ignoring drop in drag and drop file onto TextField (Mac OS X)

I want text fields to be able to handle a drop of a file from the finder.
This seems to be ignored on Mac OS X using JavaFX 8. I can't see any problems with the code, can you?
Only "Entered!" gets printed. "Dropped!" never gets printed.
...
txtSource = (TextField)scene.lookup("#txtSource");
txtSource.setOnDragEntered(this::handleEnter);
txtSource.setOnDragDropped(this::handleDrop);
...
public void handleEnter(DragEvent event) {
System.out.println("Entered!");
event.acceptTransferModes(TransferMode.ANY);
event.consume();
}
public void handleDrop(DragEvent event) {
System.out.println("Dropped!");
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasFiles()) {
File f = db.getFiles().get(0);
TextField t = (TextField)event.getAcceptingObject();
t.setText(f.getAbsolutePath());
success = true;
}
/* let the source know whether the string was successfully
* transferred and used */
event.setDropCompleted(success);
event.consume();
}
For some reason not clear to me, you need to accept the transfer mode in a dragOver handler, not a dragEntered handler:
txtSource.setOnDragOver(this::handleEnter);
// txtSource.setOnDragEntered(this::handleEnter);

Java FX Textarea performance issue in .jar

I have a TextArea that I would like to be able to append characters or words to over a period of time. I use Timer from java.util and when I run application in Eclipse everthing works ok, but when I export application into .jar I have performance issue.
Here is video from Eclipse:
http://pl.tinypic.com/r/4ftw1f/8
Here is .jar:
http://pl.tinypic.com/r/6zmoon/8
And code:
#FXML
private TextArea textarea;
public void start(KeyEvent keyEvent)
{
if (keyEvent.getCode() == KeyCode.ENTER)
{
new Timer().schedule(
new TimerTask() {
int i;
#Override
public void run() {
textarea.appendText("hey" + i + "\n");
i++;
}
}, 0, 500);
}
}
Your code has threading issues: in Java 8 it will just throw IllegalStateExceptions as you are trying to update the UI from a background thread. You need
if (event.getCode() == KeyCode.ENTER)
{
new Timer().schedule(
new TimerTask() {
int i;
#Override
public void run() {
String message = "hey"+i+"\n";
Platform.runLater(() -> textArea.appendText(message));
i++;
}
}, 0, 500);
}
I don't know if that will fix your performance issue or not. Appending text to a text area essentially involves doing lots of string concatenation; eventually (as the text in the text area gets long) this is going to be prohibitive. You might want to use a virtualized control (such as ListView), depending on the functionality you need.

Simple navigation in Windows 8 web view

I'm working on porting a Windows Phone 8 application to tablet, and I've bumped into a problem with the WebView API. In Windows Phone 8 and Windows 8.1, the WebBrowser and WebView controls both have a GoBack() method. However, I need my application to be compatible for Windows 8, whose WebView API does not have such a method. Are there any alternatives/workarounds that anyone's used for Windows 8 apps?
In the end I just ended up writing a wrapper for the WebView to manage the navigation stack. Here's the relevant code, for anyone who's interested. Note that I only needed to handle backwards navigation, so I used a Stack. If forwards navigation is also required, it'd probably make sense to replace the Stack with a List and store the index of the current page instead.
public class WebViewWrapper
{
private Stack<Uri> _navigationStack;
private Uri _currentUri;
public WebView WebView { get; private set; }
public bool CanGoBack
{
get { return _navigationStack.Count > 0; }
}
public WebViewWrapper(WebView _webView)
{
_navigationStack = new Stack<Uri>();
WebView = _webView;
WebView.LoadCompleted += (object s, NavigationEventArgs e) => {
if (_currentUri != null)
{
_navigationStack.Push(_currentUri);
}
_currentUri = e.Uri;
};
}
public void GoBack()
{
if (CanGoBack)
{
_currentUri = null;
WebView.Navigate(_navigationStack.Pop());
}
}
}
An example of usage would be as follows:
// Code behind for a view called WebBrowserPage
public sealed partial class WebBrowserPage : Page
{
private WebViewWrapper _webViewWrapper;
public WebBrowserPage()
{
// webView is a WebView in the xaml with x:Name="webView"
_webViewWrapper = new WebViewWrapper(webView);
}
// Other code for navigating to a Uri specified in a ViewModel.
// Event handler for a back button press
private void BackButton_Click(object sender, RoutedEventArgs e)
{
if (_webViewWrapper.CanGoBack)
{
_webViewWrapper.GoBack();
}
else
{
// Code that executes a command in the ViewModel to leave the WebBrowserPage
}
}
}
WinRT XAML Toolkit has a WebBrowser control that does some of that, but I haven't used it in any app, so I can't vouch for its quality.

Add a notification icon at the status bar in BlackBerry JDE 4.5.0

I'm writing a Java application in BlackBerry JDE 4.5 that will start listening for some event at the start up. I want to display a small icon at the status bar.
I know its support in version 4.6.0 of the BlackBerry API set with ApplicationIcon, ApplicationIndicator and ApplicationIndicatorRegistry classes but which classes are there in BlackBerry JDE 4.5.0 API set?
Update
I think some support is there for 4.5.0 as I'm using Blackberry Pearl 8100 with OS v4.5.0.81 which displays Notification Icons at status bar for any incoming messages or calls.
I made the Alternale Entry point & Main CLDC app like this article below,
How To - Setup an alternate entry point for my application
I have got an article as,
How to - Make a running UI application go to the background and resume in the foreground
in which its said that
The alternate entry is going to call the main method with the parameter that is passed in, regardless of whether the application is running.
But in my case the main() is not getting called when I click on appIcon when the app is running in background.
It only updates appIcon & appName which is previously set in Alternate Entry Point.
So I m not getting where the control goes if its not calling main() when clicked on updatedIcon?
Is anyone has any idea on this issue?
I updated the appIcon & appName.
Now what I want is "When clicked on updatedIcon a particular screen should be opened & when the user goes back to Main Menu the app should get its original Icon, app name & the flow should go through main() when clicked on original app Icon"
I was thinking when I click on updated appIcon the control will go to main() but instead of calling main() it says,
Starting AppName
AppName already running
& directly it goes to first screen. and when I come back to Main Menu the app has updated icon & name
So how to get it?
Unfortunately it's not possible. What you can do is update application icon.
Also there are alternative ways of notification:
Notification Service for Blackberry OS 4.5 application
Update Application Icon
alt text http://img211.imageshack.us/img211/4527/icoupdate1.jpgalt text http://img697.imageshack.us/img697/3981/icon.jpgalt text http://img687.imageshack.us/img687/256/iconactive.jpgalt text http://img130.imageshack.us/img130/3277/icoupdate2.jpgalt text http://img691.imageshack.us/img691/6459/icoupdate3.jpg
Background running application:
public class NotifIconSrvc extends Application {
private int mCount = 0;
private int mSize = 0;
public NotifIconSrvc() {
Timer timer = new Timer();
timer.schedule(sendEventTask, 1000, 3000);
}
TimerTask sendEventTask = new TimerTask() {
public void run() {
// Post the GlobalEvent.
// Long = ci.samples.45.notificon
ApplicationManager.getApplicationManager().postGlobalEvent(
0x5a9f7caa171ab7b8L, mCount++, mSize++);
}
};
public static void main(String[] args) {
NotifIconSrvc app = new NotifIconSrvc();
app.enterEventDispatcher();
}
}
Main application:
public class NotifIconApp extends UiApplication
implements GlobalEventListener {
private Bitmap mIcon = Bitmap.getBitmapResource("icon.png");
private Bitmap mIconActive =
Bitmap.getBitmapResource("icon_active.png");
private Scr mScreen = new Scr();
public NotifIconApp() {
addGlobalEventListener(this);
pushScreen(mScreen);
}
public static void main(String[] args) {
NotifIconApp app = new NotifIconApp();
app.enterEventDispatcher();
}
public void eventOccurred(long guid, int count, int size,
Object object0, Object object1) {
if (0x5a9f7caa171ab7b8L == guid) {
Bitmap icon = getUpdateIconBitmap(mIcon, count, size);
HomeScreen.updateIcon(icon);
Bitmap rolloverIcon =
getUpdateIconBitmap(mIconActive, count, size);
HomeScreen.setRolloverIcon(rolloverIcon);
mScreen.updateScreen(count, size);
}
}
private Bitmap getUpdateIconBitmap(Bitmap bmp, int count, int size) {
int width = bmp.getWidth();
int height = bmp.getHeight();
Bitmap iconBmp = new Bitmap(width, height);
Graphics g = new Graphics(iconBmp);
XYRect rect = new XYRect(0, 0, width, height);
g.drawBitmap(rect, bmp, 0, 0);
g.setFont(g.getFont().derive(Font.BOLD, 20, Ui.UNITS_px,
Font.ANTIALIAS_STANDARD, Font.COLORED_OUTLINE_EFFECT));
String text = Integer.toString(count);
g.setColor(Color.BLACK);
g.drawText(text, 0, 2);
text = Integer.toString(size) + " Kb";
g.setColor(Color.GREEN);
g.drawText(text, 0, height - 22);
return iconBmp;
}
}
class Scr extends MainScreen {
LabelField mMessages;
String mLabelText = "message count: ";
String mTitleText = "message counter";
public Scr() {
add(mMessages = new LabelField(mLabelText));
setTitle(mTitleText);
}
void updateScreen(int count, int size) {
StringBuffer sb = new StringBuffer(Integer.toString(count));
sb.append("/");
sb.append(Integer.toString(size));
sb.append("Kb");
String text = sb.toString();
setTitle(mTitleText + "(" + text + ")");
mMessages.setText(mLabelText + text);
}
protected void makeMenu(Menu menu, int instance) {
super.makeMenu(menu, instance);
menu.add(mMenuGoBG);
}
MenuItem mMenuGoBG = new MenuItem("go background", 0, 0) {
public void run() {
UiApplication.getUiApplication().requestBackground();
}
};
}

Resources