JOptionPane button size (Nimbus LAF) - java

Recently I've been working on a Swing project with Nimbus Look and Feel. I want to set all buttons in a JOptionPane to have the same size, but in vain.
import javax.swing.*;
public class NimbusTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if (("Nimbus").equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
UIManager.put("OptionPane.sameSizeButtons", true);
String[] options = new String[]{"--------------------","short","1"};
int option = JOptionPane.showOptionDialog(null, "Nimbus problem", "JOptionPane", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]);
}
});
}
}
What I want is a JOptionPane with three buttons having the same size. However, I got the following result:
My code UIManager.put("OptionPane.sameSizeButtons", true); seems to be ignored. What should I do to create a JOptionPane with same size buttons if I don't want to recreate a JOptionPane-like dialog?

Replace
UIManager.put("OptionPane.sameSizeButtons", true);
with
UIManager.getLookAndFeelDefaults().put("OptionPane.sameSizeButtons", true);
And it works like a charm

Related

How to detect changes in text in many JTextPane

I would like to create simply text editor with dynamic amount of tabs. Every tab consist of text field, where someone can load text file and edit or write own text.
I would like to detect changes in tabs, I mean when someone change file and wants close then I'd like to show a dialog about whether you want save changes or no. this is reason why I'd like to follow changes which user committed.
So I have
JTabbedPane tabbedPane with JtextPane textPane
private LinkedList<Boolean> changedList = new LinkedList<Boolean>(); // here I thought of collecting information about changes but it was silly idea.
This is function which I create new Tab
public void newTab()
{
tabbedPane.addTab("tab-" + counter++, new JTextPane());
int totalTabs = tabbedPane.getTabCount();
selected = tabbedPane.getComponentAt(totalTabs-1);
changedList.add( totalTabs-1, false);
textPane = (JTextPane)selected;
textPane.getDocument().addDocumentListener(this);
}
these are function from interface
#Override
public void insertUpdate(DocumentEvent e)
{
changedList.add(tabbedPane.getSelectedIndex(), true);
}
#Override
public void removeUpdate(DocumentEvent e)
{
changedList.add(tabbedPane.getSelectedIndex(), true);
}
#Override
public void changedUpdate(DocumentEvent e)
{
changedList.add(tabbedPane.getSelectedIndex(), true);
}
This is how I've tried to save
public void saveAfterChange()
{
if (changedList.get(tabbedPane.getSelectedIndex()))
{
int reply = JOptionPane.showConfirmDialog(null, "Save?", null, JOptionPane.YES_NO_OPTION);
if (reply == JOptionPane.YES_NO_OPTION)
{
save();
}
}
}

Close SWT shell by clicking outside of it

I have this JFace dialog:
setShellStyle(SWT.APPLICATION_MODAL | SWT.CLOSE);
setBlockOnOpen(false);
Is there a way to make it close by clicking somewhere outside the dialog?
Maybe something like listening for a click event on the whole screen and detecting if it's outside the dialog, and then closing.
You can attach an SWT.Deactivate listener to the underlying Shell of the dialog.
To attach the listener, you could override Window::configureShell like this:
#Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
shell.addListener(SWT.Deactivate, event -> shell.close());
}
And here a standalone SWT example to illustrate the bare mechanism:
Display display = new Display();
Shell parentShell = new Shell(display);
parentShell.setSize(500, 500);
parentShell.open();
Shell shell = new Shell(parentShell);
shell.addListener(SWT.Deactivate, event -> shell.close());
shell.setSize(300, 300);
shell.setText("Closes on Deactivate");
shell.open();
while (!parentShell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
With the Dialog being modal I believe that causes some challenges using the Shell of the base application to listen for MouseEvents because the Dialog intercepts them.
If you're not opposed to using an additional library you could consider using JNativeHook to listen for global mouse click events. This would allow you to listen for a click anywhere on the computer and close the dialog if the click occurred outside the dialog bounds, if that's what you're looking for.
For example:
GlobalScreen.addNativeMouseListener(new NativeMouseInputAdapter() {
public void nativeMouseClicked(final NativeMouseEvent nativeMouseEvent) {
display.syncExec(new Runnable() {
public void run() {
if (dialog.getShell() == null || dialog.getShell().isDisposed()) {
return;
}
// Close the dialog if there is a mouse click outside the bounds of the dialog
if (!dialog.getShell().getBounds().contains(awtToSwtPoint(nativeMouseEvent.getPoint()))) {
dialog.close();
}
}
});
}
});
Other than that, I'm not aware of a way to listen to mouse clicks that are outside of the base application / anywhere on the screen.
Full example:
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
import org.jnativehook.mouse.NativeMouseEvent;
import org.jnativehook.mouse.NativeMouseInputAdapter;
public class DialogCloseTest {
private final Display display;
private final Shell shell;
public DialogCloseTest() {
display = new Display();
shell = new Shell(display);
shell.setSize(450, 450);
final Dialog dialog = new MyDialog(shell);
dialog.open();
registerNativeHook();
GlobalScreen.addNativeMouseListener(new NativeMouseInputAdapter() {
public void nativeMouseClicked(final NativeMouseEvent nativeMouseEvent) {
display.syncExec(new Runnable() {
public void run() {
if (dialog.getShell() == null || dialog.getShell().isDisposed()) {
return;
}
// Close the dialog if there is a mouse click outside the bounds of the dialog
if (!dialog.getShell().getBounds().contains(awtToSwtPoint(nativeMouseEvent.getPoint()))) {
dialog.close();
}
}
});
}
});
}
private org.eclipse.swt.graphics.Point awtToSwtPoint(final java.awt.Point point) {
return new org.eclipse.swt.graphics.Point(point.x, point.y);
}
private static void registerNativeHook() {
try {
GlobalScreen.registerNativeHook();
} catch (NativeHookException ex) {
System.err.println("There was a problem registering the native hook.");
System.err.println(ex.getMessage());
System.exit(1);
}
}
private static void unregisterNativeHook() {
try {
GlobalScreen.unregisterNativeHook();
} catch (NativeHookException e) {
System.err.println("There was a problem unregistering the native hook.");
System.err.println(e.getMessage());
}
}
private static class MyDialog extends Dialog {
MyDialog(final Shell parent) {
super(parent);
}
#Override
protected void configureShell(final Shell shell) {
super.configureShell(shell);
setShellStyle(SWT.APPLICATION_MODAL | SWT.CLOSE);
setBlockOnOpen(false);
}
}
public void run() {
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
unregisterNativeHook();
}
public static void main(String... args) {
new DialogCloseTest().run();
}
}
Note: This will close the Dialog even if it is not visible (eg. if you alt-tab away), so you could add some logic to check whether the dialog is visible as well, if you would like)

rerun swing JFrame when click JOptionPane

I have a swing JFrame and in a some place of the code i need to display a JOptionPane for the user to select:
if yes - I need ht JFrame to run again and exit the existing one
if no - this is solved I just need to exit.
here is a JFrame code:
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainFrame frame = new MainFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
and here is the JOptionPane code which i created:
int ok = JOptionPane.showConfirmDialog(null, "would you like to enable USB in your device?", "USB", JOptionPane.YES_NO_OPTION);
if (ok==JOptionPane.YES_OPTION){
Thread t = new Thread(){
public void run(){
String[] args = { };
MainFrame f = new MainFrame();
f.main(args);
}
}.start();
}
else if(ok==JOptionPane.NO_OPTION){
System.exit(ok);
}
I created the thread and it is opening another JFrame but not closing the existing one!
Thanks for any help :)

Icons on JOptionPane

Sorry, this is really basic. My first experience with Java Swing using Eclipse. I'm trying to write a very simple JOptionPane. I want the question mark icon to appear, but all I am getting is the Java coffee cup icon. What am I doing wrong? Thanks!
Object[] options = {"Encrypt", "Decrypt"};
int n = JOptionPane.showOptionDialog(new JFrame(),
"What Do You Want to Do?",
"Crypto",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null, //do not use a custom Icon
options, //the titles of buttons
options[0]); //default button title
Please have a look at How to Set the Look and Feel
Try with different themes
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
// Set Motif L&F on any platform
// UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
// Set cross-platform Java L&F (also called "Metal")
// UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
// Set System L&F
//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
Object[] options = { "Encrypt", "Decrypt" };
JOptionPane.showOptionDialog(new JFrame(), "What Do You Want to Do?", "Crypto",
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, // do not use a
// custom Icon
options, // the titles of buttons
options[0]); // default button title
}
});
With different themes:

How to Set Focus on JTextField?

I make my game run without mouse so using pointer is not a choice. High Score menu will show when player lose.
this is my code
highScore=new MyTextField("Your Name");
highScore.addKeyListener(this);
highScore.setFont(font);
highScore.requestFocusInWindow();
I have tried
highScore.setFocusable(true);
highScore.requestFocusInWindow();
highScore.requestFocus(true);
highScore.requestFocus();
but still not gained focus on my JTextField.
How to focus it?
If you want your JTextField to be focused when your GUI shows up, you can use this:
in = new JTextField(40);
f.addWindowListener( new WindowAdapter() {
public void windowOpened( WindowEvent e ){
in.requestFocus();
}
});
Where f would be your JFrame and in is your JTextField.
if is there only one Top-Level Container then last lines in GUI constructor would be for example
.
.
.
myFrame.setVisible(true);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
myComponent.grabFocus();
myComponent.requestFocus();//or inWindow
}
});
public void actionPerformed(ActionEvent arg0)
{
if (arg0.getSource()==clearButton)
{
enterText.setText(null);
enterText.grabFocus(); //Places flashing cursor on text box
}
}
Try this one,
myFrame.setVisible(true);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
myComponent.grabFocus();
myComponent.requestFocus();//or inWindow
}
});
If the page contains multiple item and like to set the tab sequence and focus I will suggest to use FocusTraversalPolicy.
grabFocus() will not work if you are using FocusTraversalPolicy.
Sample code
int focusNumber = 0;
Component[] focusList;
focusList = new Component[] { game, move, amount, saveButton,
printButton, editButton, deleteButton, newButton,
settingsButton };
frame.setFocusTraversalPolicy(new FocusTraversalPolicy() {
#Override
public Component getLastComponent(Container aContainer) {
return focusList[focusList.length - 1];
}
#Override
public Component getFirstComponent(Container aContainer) {
return focusList[0];
}
#Override
public Component getDefaultComponent(Container aContainer) {
return focusList[1];
}
#Override
public Component getComponentAfter(Container focusCycleRoot,
Component aComponent) {
focusNumber = (focusNumber + 1) % focusList.length;
if (focusList[focusNumber].isEnabled() == false) {
getComponentAfter(focusCycleRoot, focusList[focusNumber]);
}
return focusList[focusNumber];
}
#Override
public Component getComponentBefore(Container focusCycleRoot,
Component aComponent) {
focusNumber = (focusList.length + focusNumber - 1)
% focusList.length;
if (focusList[focusNumber].isEnabled() == false) {
getComponentBefore(focusCycleRoot, focusList[focusNumber]);
}
return focusList[focusNumber];
}
});
In my case nothing above worked untill I called requestFocus() AFTER my constructor has returned.
MyPanel panel = new MyPanel(...);
frame.add(panel);
panel.initFocus();
MyPanel.initFocus() would have:
myTextField.requestFocus();
And it works.
This code mouse cursor “jtextfield” “Jcombobox” location focused
try {
Robot robot = new Robot();
int x = Jtextfield.getLocationOnScreen().x;
int y= Jtextfield.getLocationOnScreen().y;
JOptionPane.showMessageDialog(null, x+"x< - y>"+y);// for I location see
robot.mouseMove(x, y);
} catch (AWTException ex) {
ex.printStackTrace();
}
It was not working for me when tried to use:
JOptionPane.showConfirmDialog(...)
But -
I found a solution !
Very primitive, but works.
Just jump to the field by java.awt.Robot using key "Tab".
For example:
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_TAB);
robot.delay(100);
robot.keyRelease(KeyEvent.VK_TAB);
If you should press multiple times on "Tab" to get your Component you can use below method:
GUIUtils.pressTab(3);
Definition:
public static void pressTab(int amountOfClickes)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
try
{
Robot robot = new Robot();
int i = amountOfClickes;
while (i-- > 0)
{
robot.keyPress(KeyEvent.VK_TAB);
robot.delay(100);
robot.keyRelease(KeyEvent.VK_TAB);
}
}
catch (AWTException e)
{
System.out.println("Failed to use Robot, got exception: " + e.getMessage());
}
}
});
}
If your Component location is dynamic, you can run over the while loop without limitation, but add some focus listener on the component, to stop the loop once arrived to it.
While yourTextField.requestFocus() is A solution, it is not the best since in the official Java documentation this is discourage as the method requestFocus() is platform dependent.
The documentation says:
Note that the use of this method is discouraged because its behavior is platform dependent. Instead we recommend the use of requestFocusInWindow().
Use yourJTextField.requestFocusInWindow() instead.
How about put jTextField.requestFocusInWindow(); into jTextField FocusLost event?
Works for me
have 5 controls on JPanel
Soon as click on MessageBox, focus lost on jTextField.
Used all the suggested codes but no luck
Only above method works my case.

Categories

Resources