So i'm writing a program that saves mouse button (currently just mousePressed, but will add mouseReleased once this will work) status to log file. How do i do that?
Current code:
import static com.sun.java.accessibility.util.AWTEventMonitor.addMouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class mouse {
public static void main(String[] args) throws InterruptedException{
mouse();
}
public static void mouse() throws InterruptedException{
for(int i=0;i<10000;i++){
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
writeToFile(me); //writeToFile saves the me value to txt
}
});
TimeUnit.MILLISECONDS.sleep(1); // time delay, so it saves every 1ms
}
}
public static void writeToFile(MouseEvent me){
try{
String data =" "+me+" ";
File file =new File("log.txt");
//if log.txt doesn't exist, it makes it
if(!file.exists()){
file.createNewFile();
}
//true = write
FileWriter fileWritter = new FileWriter(file.getName(),true);
BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
bufferWritter.write(data);
bufferWritter.close();
}catch(IOException e){
}
}
}
The program compiles and runs, but it doesn't do anything.
I thank you all in advance.
If you're not trying to create a GUI and instead want to log general Mouse position, then adding a MouseListener to your class will do nothing of use. Instead understand that Java is not optimized for this type of program, and you would likely have to use JNA or JNI to trap the OS's mouse handling code. If on the other hand you wish to trap the mouse usage of a Swing GUI, then you first need to create a Swing GUI and then add your MouseListener to it. I'd advise your reading the MouseListener Tutorial for more on this.
Edit
You state:
Ultimately, it will be a part of GUI application, i'm just trying to make a concept of it.
Please understand that a MouseListener will not be functional without adding it to a Component that accepts one, that extends ultimately from the Component type, and that is displayed in a GUI. So in order to test your concept, you will again need to create a Swing GUI and add a MouseListener to one of the visualized components of your GUI. Again, please read the MouseListener tutorials.
About overwriting the file, it doesn't, i took it from my previous program, and it works properly.
Sorry, my bad -- I misread your code.
Edit 2
And as noted in comment, the listener should not have loops, but rather should respond to mouse EVENTS. For example, the following code listens for mouse press, release, and drag and displays the information in a JTextArea. It would be trivial to change this to write to file:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class SimpleMouseListenerEg extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = 400;
private JPanel listenedToPanel = new JPanel();
private JTextArea textArea = new JTextArea(10, 25);
public SimpleMouseListenerEg() {
listenedToPanel.setBorder(BorderFactory.createTitledBorder("Listened To Panel"));
MouseAdapter myMouseAdapter = new MyMouseAdapter();
listenedToPanel.addMouseListener(myMouseAdapter);
listenedToPanel.addMouseMotionListener(myMouseAdapter);
textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setLayout(new BorderLayout());
add(listenedToPanel, BorderLayout.CENTER);
add(scrollPane, BorderLayout.EAST);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
// a combination MouseListener and MouseMotionListener
private class MyMouseAdapter extends MouseAdapter {
private String template = "%-10s [%03d, %03d]%n";
#Override
public void mousePressed(MouseEvent mEvt) {
String text = String.format(template, "Pressed", mEvt.getX(), mEvt.getY());
textArea.append(text);
}
#Override
public void mouseReleased(MouseEvent mEvt) {
String text = String.format(template, "Released", mEvt.getX(), mEvt.getY());
textArea.append(text);
}
#Override
public void mouseDragged(MouseEvent mEvt) {
String text = String.format(template, "Dragged", mEvt.getX(), mEvt.getY());
textArea.append(text);
}
}
private static void createAndShowGui() {
SimpleMouseListenerEg mainPanel = new SimpleMouseListenerEg();
JFrame frame = new JFrame("SimpleMouseListenerEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
I am trying to develop a main menu for a game in java, but my JMenuItems wouldn't listen to the KeyEvents and I don't understand why. Note that I don't want to set any JMenuBars nor JMenus as this program is intended to be a game used with screen readers, so I don't want accessibility roles to be read. Furthermore, adding a menu complicates the access to the elements with the keyboard and I want the focus to start in the first option.
This is my code:
import java.util.Set;
import java.util.HashSet;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.MenuKeyEvent;
import javax.swing.event.MenuKeyListener;
public class Screen {
public Screen() {
// Accept arrow keys as focus traversal keys
Set<AWTKeyStroke> set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTrave rsalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("DOWN"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,set);
set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("UP"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,set);
// definition of Menu Items
JMenuItem mi=new JMenuItem("play");
JMenuItem mi2=new JMenuItem("exit");
mi.setFocusable(true);
mi2.setFocusable(true);
// Attempt with MenuKeyListener
mi.addMenuKeyListener(new MenuKeyListener() {
public void menuKeyReleased(MenuKeyEvent e) {
System.out.println("Play released");
}
public void menuKeyTyped(MenuKeyEvent e) {}
public void menuKeyPressed(MenuKeyEvent e) {}
});
// Attempt with ActionListener
mi2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
mi.setVisible(true);
mi2.setVisible(true);
JPanel mp = new JPanel();
JFrame mf = new JFrame("Game");
mf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mp.add(mi);
mp.add(mi2);
mf.add(mp);
mf.setVisible(true);
}
public static void main(String args[]) {
new Screen();
}
}
I've tried with both ActionListener and MenuKeyListener, with and without the JPanel, changing visibilities... I also tried to use KeyEventDispatcher but I didn't know how to send a KeyEvent to the component that returns KeyboardFocusManager.getFocusOwner().
Please help.
There's a lot to help with in this case. For starters,
public static void main(String args[]) {
new Screen();
}
is wrong. It is not appropriate to perform any operation that alters the Swing layout or presentation on the main thread. Instead do
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Screen();
}
});
}
if you decide that you want to put swing calls into an object's constructor in this way.
Ideally your Screen would be a JFrame but one that is customized to meet your needs. That means you might want to create a new class GamePanel that extends JPanel
public class Screen extends JFrame {
public Screen() {
super("Game"); // to remind us that the JFrame is created
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new GamePanel());
pack();
setVisible(true);
}
}
public class GamePanel extends JPanel {
public GamePanel() {
super();
}
}
Now, if you want that panel to listen to keys, you need to add a KeyListener interface. This only gives it the capability to listen, it doesn't make it listen.
public class GamePanel extends JPanel implements KeyListener {
...
public void keyTyped(KeyEvent e) {
System.out.println("KEY TYPED: " + e);
}
public void keyPressed(KeyEvent e) {
System.out.println("KEY PRESSED: " + e);
}
public void keyReleased(KeyEvent e) {
System.out.println("KEY RELEASED: " + e);
}
}
Now you can add your key listener to the Screen or to the GamePanel (it will listen to itself). Whenever the focus is in one of these items, and a key is pressed, the even will be routed to the listener.
public class GamePanel extends JPanel implements KeyListener {
public GamePanel() {
super();
addKeyListener(this);
}
...
}
Ideally, you might want to not combine your key listener with the panel itself, but make it a "Command Processor" of some sort. In that case, remove the KeyListener code from the JPanel and make a completely new CommmandHandler object that implements KeyListener.
As far as Actions go, they are convenience items that pre-configure menu entries with lots of things (icons, acceleration keys, text, callback functions). If you are avoiding menus for whatever reason, you will find that much of their utility in setting up menus is misdirected for your purpose. Effectively, they are configuration entries that configure the MenuItem objects to handle a key (through the KeyListener interface and then dispatch a swing Event object. This provide "better than key" tracking of items through an application as it converts a keyboard letter k to a class ActionEvent which is passed to the registered "action handler" typically a subclass of AbstractAction.
An example of an Action would be
public class MoveLeft extends AbstractAction { // which extends ActionListener
private final GameState gameState;
public MoveLeft(GameState gameState) {
super("move left", new ImageIcon(MoveLeft.class.getResource("/images/moveleft.png"));
putValue("SHORT_DESCRIPTION", "left");
putValue("MNEMONIC_KEY", "l");
this.gameState = gameState;
}
public void actionPerformed(ActionEvent e) {
gamestate.getSelected().moveLeft();
}
}
Assuming you wanted this convenience, you would initialize your CommandHandler with Actions, maybe like so:
public CommandHandler implements KeyListener {
private int actionId;
...
public void addAction(Action action) {
handlers.put(action.getValue("MNEMONIC_KEY")., action);
}
public void keyTyped(KeyEvent e) {
Action action = handlers.get(String.valueOf(e.getKeyChar());
ActionEvent event = new ActionEvent(this, id, action.getValue("NAME"));
action.actionPerformed( event );
}
}
As you can see, the added convenience of having Actions defined for the actions within your game is a balanced by making your components that use them be configured by them (and using them in the KeyListener implementations).
For large projects, the simplicity of having all your actions listed generally makes creating Actions well worth the effort; but, for smaller projects that are mostly using custom components, the added one-time-cost of making the KeyListener components use actions might outweigh the benefits.
Don't use JMenuItem this way, that's not how it's intended to be used
Instead, I'd start with JButton. The following makes use of your focus transversal code, the Action API and the key bindings API
import java.awt.AWTKeyStroke;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
Set<AWTKeyStroke> set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("DOWN"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set);
set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("UP"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set);
Action playAction = new AbstractAction("Play") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("play");
}
};
playAction.putValue(Action.MNEMONIC_KEY, (int)'P');
Action exitAction = new AbstractAction("Exit") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("exit");
}
};
exitAction.putValue(Action.MNEMONIC_KEY, (int)'x');
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0), "play");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, 0), "exit");
am.put("play", playAction);
am.put("exit", exitAction);
JButton playButton = new JButton(playAction);
JButton exitButton = new JButton(exitAction);
add(playButton, gbc);
add(exitButton, gbc);
}
}
}
Now, you could do something similar with JLabel, but, JLabel isn't focusable by default, nor does it render any kind of focus indication. Instead, I might be tempted to just strip down a JButton so it didn't paint its border or content/background instead
I am programming a multiplication app for very large integers, I need to update every sigle step of the multiplication in a Swing component ( I created a JPane extended class with a JTextArea in it, then add it to the JFrame inside a ScrollPane). The issue is that this Swing component only updates once the multiplication algorithm is done. I tried using a Thread that would call repaint method of the Pane every 10 ms, but it did not work. The next is a sample of the problem.
This is the main Frame class:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Frame extends JFrame implements ActionListener{
private Console console;
private JButton calculate;
private Calculator calculator;
public Frame(){
console=new Console();
calculate=new JButton("Calculate");
calculate.addActionListener(this);
calculate.setActionCommand("");
calculator=new Calculator(this);
this.setLayout(new BorderLayout());
this.add(console,BorderLayout.CENTER);
this.add(calculate, BorderLayout.NORTH);
this.setTitle("Frame");
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(new Dimension(500,500));
this.setLocationRelativeTo(null);
}
public void writeOnConsole(String txt){
console.write(txt);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getActionCommand().equals("")){
console.clear();
calculator.calculate();
}
}
public static void main(String[] args) {
new Frame();
}
}
This is the Console Class
import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;
public class Console extends JPanel{
private JTextArea area;
public Console(){
this.setBorder(new TitledBorder("Console:"));
area=new JTextArea();
this.setLayout(new BorderLayout());
JScrollPane scroll=new JScrollPane(area);
this.add(scroll,BorderLayout.CENTER);
}
public void clear(){
area.setText("");
}
public void write(String txt){
area.append(txt+"\n");
}
}
Finally, this is the Calculator class (the one responsible for calling the writing)
public class Calculator {
private Frame parent;
public Calculator(Frame f){
parent=f;
}
public void calculate(){
for (int i = 0; i <= 1000000; i++) {
parent.writeOnConsole("Iteration "+i);
}
}
}
Note that if you run the program, the GUI will freeze until the Calculator class is done with the loop.
if you have a layout like a BorderLayout and you want to update it inside the JFrame do as bellow
JFrame frame = new JFrame();
BorderLayout layout = new BorderLayout();
layout.layoutContainer(frame.getContentPane());// use the frame as the border layout container
else you can use JFrame pack() method. The pack method packs the components within the window based on the component’s preferred sizes. it's not for updating but it updates the JFrame which is kind of a trick
JFrame frame = new JFrame();
//change the components dynamically
frame.pack();
or use Container methdod validate(). Validating a container means laying out its subcomponents. Layout-related changes, such as setting the bounds of a component, or adding a component to the container.
JFrame frame = new JFrame();
Container container = frame.getContentPane();
container.validate();
or if you want to update an specific component use
Component component = new JPanel();
component.repaint();
If this component is a lightweight component, repaint() method causes a call to this component's paint method as soon as possible .
or if you want for example numerous changes happen one by one dynamically then you could use the code below which is completely different from the things i said above. for that you could use platform.runlater() inside another thread which deals with everything that is about to change in realtime
new Thread(new Runnable()
{
#Override
public void run()
{
Platform.runLater(new Runnable()//use platform.runlater if you are using javafx
{
#Override
public void run()
{
try
{Thread.sleep(50);}catch(Exception e){}//use it in for loop where changes happen
//do some realtime change of components
}
});
}).start();
your Console class would be
import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;
public class Console extends JPanel{
private JTextArea area;
public Console(){
this.setBorder(new TitledBorder("Console:"));
area=new JTextArea();
this.setLayout(new BorderLayout());
JScrollPane scroll=new JScrollPane(area);
this.add(scroll,BorderLayout.CENTER);
}
public void clear(){
area.setText("");
}
public void write(String txt){
area.append(txt+" "+"\n");
}
}
and the Calculator class is
public class Calculator {
private Frame parent;
public Calculator(Frame f){
parent=f;
}
public void calculate(){
new Thread(new Runnable() {
#Override
public void run()
{
for (int i = 0; i <= 100; i++) {
try
{
Thread.sleep(50);
}
catch(Exception e)
{
e.printStackTrace();
}
parent.writeOnConsole("Iteration "+i);
}
}
}).start();
}
}
as you can see i used another thread to do the changes
try the update method to call paint method for maintain every change
I'm sure someone has asked this question before, but my google-fu is not strong today.
I have a JFrame that uses a CardLayout as its manager. How do I run a "Start" method when I switch to each JPanel without using a switch?
The code I use to add the frames to the layout is:
/**
* Adds JPanels to the Card Layout.
* #param panel is the JPanel to add to the layout.
* #param windowName is the identifier used to recognise the Panel.
*/
public final void addToCards(final JPanel panel, final WindowNames windowName) {
view.getBasePanel().add(panel, windowName.getValue());
}
The code I use to switch the layout is:
/**
* Method to change the JPanel currently visible on the BasePanel.
* #param windowName is the name of the JPanel to change to.
*/
public final void changePanel(final WindowNames windowName) {
view.getCardLayout().show(view.getBasePanel(), windowName.getValue());
}
Currently I have an ActionListener set that will call the switch code, but I can't work out how to call the "Start" method within the screen that it will be switching to.
I have an interface setup for each of the JPanels so that the method name will be identical in each.
You can just use a ComponentListener for the panel(s). When the panel becomes the view of the CardLayout, it will fire a component event and handled by componentShown in your listener (as well as the panel taken out of view, handling the componentHidden). Call your start() method there. This way you don't have to explicitly call the start() when the panel changes, as it be called for you.
See How to Write Component Listeners for more details.
Here is a simple example.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Main {
private static final String PANEL_A = "panelA";
private static final String PANEL_B = "panelB";
CardLayout layout = new CardLayout();
JPanel panel = new JPanel(layout);
ComponentListenerPanel p1 = new ComponentListenerPanel(PANEL_A);
ComponentListenerPanel p2 = new ComponentListenerPanel(PANEL_B);
JButton b1 = new JButton(PANEL_A);
JButton b2 = new JButton(PANEL_B);
public Main() {
panel.add(p1, PANEL_A);
panel.add(p2, PANEL_B);
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
show(PANEL_A);
}
});
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
show(PANEL_B);
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(b1);
buttonPanel.add(b2);
JFrame frame = new JFrame();
frame.add(panel);
frame.add(buttonPanel, BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void show(String panelName) {
layout.show(panel, panelName);
}
private class ComponentListenerPanel extends JPanel {
private String panelName;
public ComponentListenerPanel(String panelName) {
this.panelName = panelName;
addComponentListener(new ComponentAdapter() {
#Override
public void componentHidden(ComponentEvent evt) {
stop();
}
#Override
public void componentShown(ComponentEvent evt) {
start();
}
});
}
public void start() {
System.out.println(panelName + " started");
}
public void stop() {
System.out.println(panelName + " stopped");
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Main();
}
});
}
}
Note you haven't actually said where the start method is, so this code/answer is just assuming you have some start method in custom panel. Hope I guessed right. In the future, or even now, you should always post an MCVE so that we don't have to do all this guessing.
I have an interface setup for each of the JPanels so that the method name will be identical in each
So then the problem is getting the current panel that is visible when the panels are swapped so you can invoke the method.
Check out Card Layout Focus for a class that extends CardLayout to provide a few helper methods to add additional functionality for the CardLayout. You would use the getCurrentCard() method.
So your changePane(...) method might be something like:
public final void changePanel(final WindowNames windowName) {
//view.getCardLayout().show(view.getBasePanel(), windowName.getValue());
RXCardLayout layout = view.getCardLayout();
layout.show(view.getBasePanel(), windowName.getValue());
MyInterface panel = (MyInterface)layout.getCurrentCard();
panel.someMethod(...);
}
Of course you would also need to use the RXCardLayout as the layout manager for your main panel.
I am very new to Java AWT. My question header must seem ridiculous to you, sorry about that. In my application I have three buttons which display different threads when clicked on. Now I want to add maybe a button or checkboxes or choicelist, etc when clicked on a particular button. For eg, if I click on yes button, it should display a choice list, something like that. How do I achieve something like that? Here is my code so far:
import java.awt.Button;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class AppWindow extends Frame implements ActionListener{
String keymsg = "Test message";
String mousemsg = "Nothing";
int mouseX=30, mouseY=30;
String msg;
public AppWindow(){
//addKeyListener(new MyKeyAdapter(this));
//addMouseListener(new MyMouseAdapter(this));
addWindowListener(new MyWindowAdapter());
}
public void paint(Graphics g){
g.drawString(msg, 150, 100);
}
//Here the window is created:
public static void main(String args[]){
AppWindow appwin = new AppWindow();
appwin.setSize(new Dimension(300,200));
appwin.setTitle("My first AWT Application");
appwin.setLayout(new FlowLayout(FlowLayout.LEFT));
appwin.setVisible(true);
Button yes,no,maybe;
yes = new Button("yes");
no = new Button("no");
maybe = new Button("maybe");
appwin.add(yes);
appwin.add(no);
appwin.add(maybe);
yes.addActionListener(appwin);
no.addActionListener(appwin);
maybe.addActionListener(appwin);
}
#Override
public void actionPerformed(ActionEvent ae) {
// TODO Auto-generated method stub
String str = ae.getActionCommand();
if(str.equals("yes")){
msg = "You pressed Yes";
}
if(str.equals("no")){
msg = "You pressed No";
}
if(str.equals("maybe")){
msg = "You pressed Maybe";
}
repaint();
}
}
class MyWindowAdapter extends WindowAdapter {
public void windowClosing(WindowEvent we){
System.exit(0);
}
}
Points describing what you should be doing :
As already mentioned by others, better to use Swing over AWT, since Swing is more advanced.
As much as possible, always try to Paint on top of a JPanel or a
JComponent, instead of Painting right on top of your JFrame, by
overriding the paintComponent(Graphics g) method of the said
JComponent/JPanel
Never call setVisible(true) on the JFrame until and unless it's
size has been established. So in general terms, this has to be the
last call, once you are done adding components to the JFrame and
the size of the JFrame has been realized by the LayoutManager.
Inside your actionPerformed(...), instead of writing all if
statement blocks, you should adhere to the if-else if statement
blocks. The benefit of this, over the former is that, at any given
time, only one event will be fired, hence once the said condition is
satisfied, you don't want your code to keep checking other
conditions, which in general is really not a good programming
practice, IMHO.
MOST IMPORTANT THING : Never make calls like pack()/setVisible(...) from within the main method, such calls belong
to the Event Dispatch Thread, and must be done on the same. Please
read Concurrency in Swing for more detail.
Have a look at the example program, for better understanding.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ComponentExample
{
private CustomPanel drawingBoard;
private JPanel contentPane;
private JButton yesButton;
private JButton noButton;
private JButton maybeButton;
private JComboBox cbox;
private ActionListener buttonAction = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
JButton button = (JButton) ae.getSource();
if (cbox.isShowing())
contentPane.remove(cbox);
if (button == yesButton)
{
drawingBoard.setText("You Pressed YES.");
contentPane.add(cbox, BorderLayout.PAGE_END);
}
else if (button == noButton)
drawingBoard.setText("You Pressed NO.");
else if (button == maybeButton)
drawingBoard.setText("You Pressed MAYBE.");
/*
* revalidate()/repaint() is needed
* when the JComponent is added or
* removed from the already
* visible Container.
*/
contentPane.revalidate();
contentPane.repaint();
}
};
public ComponentExample()
{
cbox = new JComboBox(
new String[]{"I GOT IT"
, "I STILL HAD DOUBT"});
}
private void displayGUI()
{
JFrame frame = new JFrame("Component Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = new JPanel();
contentPane.setOpaque(true);
contentPane.setBackground(Color.DARK_GRAY);
contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(5, 5));
JPanel buttonPanel = new JPanel();
buttonPanel.setOpaque(true);
buttonPanel.setBackground(Color.WHITE);
yesButton = new JButton("YES");
yesButton.addActionListener(buttonAction);
noButton = new JButton("NO");
noButton.addActionListener(buttonAction);
maybeButton = new JButton("MAY BE");
maybeButton.addActionListener(buttonAction);
buttonPanel.add(yesButton);
buttonPanel.add(noButton);
buttonPanel.add(maybeButton);
contentPane.add(buttonPanel, BorderLayout.PAGE_START);
drawingBoard = new CustomPanel();
contentPane.add(drawingBoard, BorderLayout.CENTER);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new ComponentExample().displayGUI();
}
});
}
}
class CustomPanel extends JPanel
{
private String msg;
public CustomPanel()
{
msg = "";
setOpaque(true);
setBackground(Color.WHITE);
}
public void setText(String msg)
{
this.msg = msg;
repaint();
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(300, 300));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawString(msg, getWidth() / 3, getHeight() / 3);
}
}
I don't know if I have understood the question well but... couldn't you create those elements and call their setVisible(boolean) methods to make them not visible at first, and them make them visible when user pushes buttons?
I have JScrollPane with JTextArea inside it and I am trying to set the JTextArea's orientation from right to left so the text inside it will start from the right and the scrollbar will be on the left
I've tried the following but they didn't affect the direction of the orientation:
txt.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
txt.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
txt.setAlignmentX(JTextArea.RIGHT_ALIGNMENT);
EDIT:
the two answers camickr & trashgod provided work fine but not in my program where I use my JTextArea as an object Message and pass it to OptionPane.
EDIT2:
I figured out that setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); doesn't work if I apply it on the JOptionPane contents .. is there an alternative solution to this issue?
Similar to my code:
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class TextArea extends JPanel
{
private JTextArea txt = new JTextArea();
public TextArea()
{
setLayout(new GridLayout());
txt.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
JScrollPane scroll = new JScrollPane(txt);
scroll.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
setPreferredSize(new Dimension(200,200));
this.add(scroll);
}
private void display()
{
Object[] options = {this};
JOptionPane pane = new JOptionPane();
int option = pane.showOptionDialog(null, null, "Title", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
}
public static void main(String[] args)
{
new TextArea().display();
}
}
and the scrollbar will be on the left
scrollPane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
so the text inside it will start from the right
textArea.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
The text starts on the right side, but still gets append to the end as you type instead of being inserted at the beginning of the line.
Update:
I don't know why it doesn't work in an option pane. Here is a simple solution:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
public class Test
{
public static void main(String args[]) throws Exception
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JTextArea textArea = new JTextArea(4, 20);
JScrollPane scrollPane = new JScrollPane( textArea );
JPanel panel = new JPanel();
panel.add( scrollPane );
scrollPane.addAncestorListener( new AncestorListener()
{
public void ancestorAdded(AncestorEvent e)
{
JScrollPane scrollPane = (JScrollPane)e.getComponent();
scrollPane.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
}
public void ancestorMoved(AncestorEvent e) {}
public void ancestorRemoved(AncestorEvent e) {}
});
JOptionPane.showMessageDialog(null, panel);
}
});
}
}
This seems to work.
import java.awt.ComponentOrientation;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.Locale;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/** #see http://stackoverflow.com/questions/6475320 */
public class RTLTextArea extends JPanel {
private static final String s = "مرحبا العالم";
private JTextArea jta = new JTextArea(7, 5);
private Locale arabic = new Locale("ar", "KW");
private ComponentOrientation arabicOrientation =
ComponentOrientation.getOrientation(arabic);
public RTLTextArea() {
this.setLayout(new GridLayout());
this.add(new JScrollPane(jta));
this.applyComponentOrientation(arabicOrientation);
for (int i = 0; i < 8; i++) {
jta.append(s + "\n");
}
}
private void display() {
JFrame f = new JFrame("RTLTextAre");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new RTLTextArea().display();
}
});
}
}
this line
setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT)
change the correct order of the words.
i have this result
KBytes 80.78
The following lines solved my problem:
jTextArea1.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
jTextArea1.setText(<text>);
They serve to:
setComponentOrientation() changes the orientation of the TextArea; and,
setText() refreshes TextArea immediately so it displays properly
Simply setting ComponentOrientation to RIGHT_TO_LEFT is not sufficient by itself. repaint() doesn't force the text to realign itself. A quick solution for me was to update the contents of the TextArea. That forced the text to realign itself.