java - how do jcomponents draw? - java

im wondering how a jcomponent gets painted on the screen, is it painted inside paintComponent() from Graphics? Or is it painted separately. Im asking this because its weird how a jbutton changes color on mousehover even though repaint() is never called.
Thanks for your time.

Components are painted with their paint method. repaint is just a useful method that will call paint at some point in the near future on the Event Dispatch Thread.
When the mouse enters a JButton, the following method is called (for JButtons with a default UI):
public void mouseEntered(MouseEvent e) {
AbstractButton b = (AbstractButton) e.getSource();
ButtonModel model = b.getModel();
if (b.isRolloverEnabled() && !SwingUtilities.isLeftMouseButton(e)) {
model.setRollover(true);
}
if (model.isPressed())
model.setArmed(true);
}
ButtonModel.setRollover will fire a ChangeEvent, which is handled by AbstractButton in the following way:
public void stateChanged(ChangeEvent e) {
Object source = e.getSource();
updateMnemonicProperties();
if (isEnabled() != model.isEnabled()) {
setEnabled(model.isEnabled());
}
fireStateChanged();
repaint();
}
So repaint is called when the mouse enters a JButton.

..a jbutton changes color on mousehover even though repaint() is never called.
Sure it is. And this code is evidence of that. Of course, it is not evidence on a Kindle Fire that most probably has no JRE, but then, a Kindle Fire is an entirely inappropriate tool to be using to communicate to a Q&A site while discussing technical points of a programming language that does not run on the device.
import javax.swing.*;
public class ButtonRepaint {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JButton b = new JButton("Hover Over Me!") {
#Override
public void repaint() {
super.repaint();
System.out.println("Repaint");
}
};
JOptionPane.showMessageDialog(null, b);
}
};
SwingUtilities.invokeLater(r);
}
}

Note that the paint() method that gets called belongs to the button's UI delegate, typically derived from BasicButtonUI. There's an example here using MetalButtonUI.

Related

How does this Code show that the Mouse has clicked?

Seen this somewhere in StackOverflow. Just want to know how it works...
public void mouseClicked(MouseEvent e){
int x = e.getX();
int y = e.getY();
}
x and y are coordinates and can be shown to screen using JLabel, but the method name is mouseClicked. How does java know the mouse has been clicked?
(Hope this makes sense)...
The method mouseClicked is likely from java.awt.event.MouseListener interface (https://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseListener.html)
A listener is a type of callback that follows the observer pattern, something happens, you get notified.
You can attach listener to items that support it. For example:
MouseListener listener = new MouseListener() { /* see example code below */ };
JLabel label = new JLabel("This is a clickable lable");
label.addMouseListener(listener);
See the following answer to get more info and reference to reading articles.
https://stackoverflow.com/a/17415300/132121
#transformer here is an empty implementation of the MouseListener you would create in Java code.
MouseListener listener = new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
// This is the method where you would get your callback
// whenever somebody clicked on the view that has this listener
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
};
This is an event handler. In order for it to work, it has to be "attached" to something in the front end (most likely a button, but it could be another UI element too).
Exactly how this works depends on which UI framework is being used, but since this is Java I assume it's most likely AWT. You can find more details in tutorials, e.g. here.
Incidentally, how significant the name is depends on which UI framework this is from. In Android, WPF, and ASP.NET, for example, the name of event handlers could theoretically be anything, it's mostly just a matter of convention (not actual requirement) what you call it. (Obviously, you have to be consistent with the name, though). As pointed out in the comments, though, in AWT this name is actually likely significant due to the class that contains it implementing an interface.

No keyboard input working KeyAdapter

I wrote some application and wanted to add some keyboard input to it.
My main class extends a JPanel so i could add the keyAdapter into the constructor.
The keyAdapter is a new class called "InputAdapter" extending keyadapter with it's keyPressed() and keyReleased() method. on click or release the console should print some string, e.g. here "Test"
I don't know why, but the console won't print any text. Also, when I tell it to turn a sprites visibility to false nothing happens as well.
So i guess the KeyAdapter isn't working properly, so could someone take a closer look into my codelines?
i guess this issue has nothing to do with the other implemented classes i wrote because when removing them, the issue with the non working keyboard input remains.
package com.ochs.game;
public class Game extends JPanel implements Runnable{
private static final long serialVersionUID = 1L;
public static final int WIDTH = 320;
public static final int HEIGHT = 240;
public static final int SCALE = 3;
public boolean isRunning;
public Game() {
addKeyListener(new InputAdapter());
setFocusable(true);
requestFocus();
start();
}
public void start() {
isRunning = true;
new Thread(this).start();
}
public void stop() {
isRunning = false;
}
public void run() {
init();
while(isRunning) {
update();
repaint();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
System.out.println("Thread sleep failed.");
}
}
}
public void init() {
}
public void update() {
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
}
public static void main(String[] args) {
Game gameComponent = new Game();
Dimension size = new Dimension(WIDTH*SCALE, HEIGHT*SCALE);
JFrame frame = new JFrame("Invaders");
frame.setVisible(true);
frame.setSize(size);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(gameComponent);
}
public class InputAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent arg0) {
System.out.println("Test");
}
#Override
public void keyReleased(KeyEvent arg0) {
System.out.println("Test");
}
}
}
Your code works for me:
java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.6) (6b27-1.12.6-1ubuntu0.12.04.2)
OpenJDK Client VM (build 20.0-b12, mixed mode, sharing)
Tip 1 - You should override paintComponent(Graphics g) i guess, not paint()
public void paintComponent(Graphics g){
super.paintComponent(g);
//...
}
Tip 2 - Use addNotify() on your JPanel:
public void addNotify(){
super.addNotify();
//start from here
new Thread(this).start();
}
Tip 3 - Launch your app this way, from the EDT Thread (see What does SwingUtilities.invokeLater do?)
SwingUtilities.invokeLater(new Runnable() {
public void run(){
//your code
}
});
Hope it helps!
There are many possible reasons why this might not work. KeyListener is very fussy. It requires that the component that is registered to not only be focusable, but have focus.
Even though your component seems to both these things, if, for some reason, focus is grabbed by another component, the KeyListener will stop working.
You should use requestFocusInWindow and requestFocus is unreliable, but a better solution would be to use Key bindings, which has the ability to over come all that messiness with focus...
You should avoid overriding paint and use paintComponent instead, check out Performing Custom Painting for more details.
Mixing threads with Swing is tricky, you will also want to be sure that you are not violating the single thread rules of Swing when you are updating the your state. Check out Concurrency in Swing for more details
Your basic code design is old AWT painting code. I echo everything MadProgrammer says for a better Swing design.
In addition:
there is no need for an empty init() method. Get rid of the method and the call to the method.
same for the update() method.
The big problem with the posted code is that you add the panel to the frame AFTER the frame is visible. You should always add components to the frame before making the frame visible:
JFrame frame = new JFrame("Invaders");
frame.add(gameComponent);
...
frame.setVisible(true);
Don't take the easy way out and just make the above change. Write code for a Swing program not an AWT program.

ActionListener call blocks MouseClick event

I have a window with a MenuItem "maddbound3" with the following ActionListener:
maddbound3.addActionListener
(
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
menu_addbound3();
}
}
);
When the menu is clicked this listener calls menu_addbound3() below:
void menu_addbound3()
{
while(getEditMode() != EditMode.NONE)
{
System.out.println("!... " + getEditMode());
synchronized(this)
{
try
{
wait();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
A MouseClicked event alters the value of the edit mode and issues a notifyAll() so that the while loop should exit. However, tests have shown that when the system is running through the while loop, the MouseClicked event never occurs on clicking the mouse.
Does the ActionListener block the MouseClicked event? How can I resolve this issue?
Thanks
Don't have a while(true) on the Swing event thread, and likewise don't call wait() on the Swing event thread -- you'll freeze the whole GUI making it completely unresponsive. You need to understand that the main Swing event thread or "event dispatch thread" is responsible for all Swing drawing and user interaction, and so if you tie it up with long-running or freezing code, you lock your entire GUI.
Instead, change the state of your program -- perhaps by setting a variable or two, and have the behavior of your program depend on this state. If you need more specific advice, please tell us what behavior you're trying to achieve, and we can perhaps give you a better way of doing it.
For more on the Swing event thread, please read: Lesson: Concurrency in Swing
Edit
You state:
When the user clicks the menu item I want to obtain information via a series of "discrete" mouse clicks from the window. Hence, on clicking the menu, the user would be prompted to "select a point in the window". So, what I need is for my ActionListener function (menu_addbound3) to then wait for a mouse click. Hence the wait/notify setup. A mouse click changes the edit_mode and notifyAll() causes the wait in the while loop to exit which then causes the while loop to exit and I can then prompt for my next bit of information within the menu_addbound3 function, repeating this as as I need to.
Thanks for the clarification, and now I can definitely tell you that you are doing it wrong, that you most definitely do not want to use the while loop or wait or notify. There are many ways to solve this issue, one could be to use some boolean or enum variables to give the program a state and then alter its behavior depending on the state. Your EditMode enum can be used in the MouseListener to let it know that its active, and then you could also give the MouseListener class a boolean variable windowPointSelected, set to false, and then only set it true after the first click has been made.
Edit 2
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class ProgState extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final Color EDIT_COLOR = Color.red;
private EditMode editMode = EditMode.NONE;
private boolean firstPointSelected = false;
private JMenuBar jMenuBar = new JMenuBar();
private JTextField firstPointField = new JTextField(15);
private JTextField secondPointField = new JTextField(15);
public ProgState() {
add(firstPointField);
add(secondPointField);
JMenu menu = new JMenu("Menu");
menu.add(new JMenuItem(new AbstractAction("Edit") {
#Override
public void actionPerformed(ActionEvent arg0) {
setEditMode(EditMode.EDITING);
setFirstPointSelected(false);
}
}));
jMenuBar.add(menu);
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mEvt) {
if (getEditMode() == EditMode.EDITING) {
Point p = mEvt.getPoint();
String pStr = String.format("[%d, %d]", p.x, p.y);
if (!isFirstPointSelected()) {
firstPointField.setText(pStr);
setFirstPointSelected(true);
} else {
secondPointField.setText(pStr);
setEditMode(EditMode.NONE);
}
}
}
});
}
public void setEditMode(EditMode editMode) {
this.editMode = editMode;
Color c = editMode == EditMode.NONE ? null : EDIT_COLOR;
setBackground(c);
}
public EditMode getEditMode() {
return editMode;
}
public void setFirstPointSelected(boolean firstPointSelected) {
this.firstPointSelected = firstPointSelected;
}
public boolean isFirstPointSelected() {
return firstPointSelected;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public JMenuBar getJMenuBar() {
return jMenuBar;
}
private static void createAndShowGui() {
ProgState progState = new ProgState();
JFrame frame = new JFrame("EditMode");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(progState);
frame.setJMenuBar(progState.getJMenuBar());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum EditMode {
NONE, EDITING
}
From the discussion it seems that having your class assume a number of states is the best way to proceed. We can achieve this by one or more enum variables. The reason I found this so hard to grasp initially is that I couldn't see the benefit of having all of ones code in the MouseClicked function. This is ugly and unmanageable at best.
However, using multiple enums and splitting processing into a number of external functions, we do indeed achieve a nice system for what we want.

java resizing methods

Could you tell me what methods are called upon a JFrame/JDialog after you resize it manually?
( after you resize it using the mouse cursor, while the frame is visible on the screen). I noticed that my JDialog is not valid eventhough I call validate() or revalidate() upon it, but after I resize it a bit, my frame becomes valid.
I think it is java.awt.event.ComponentListener
The listener interface for receiving component events. When the
component's size, location, or visibility changes, the relevant method
in the listener object is invoked, and the ComponentEvent is passed to
it.
For example:
public class MyFrame extends JFrame implements ComponentListener {
#Override
public void componentResized(ComponentEvent e) {
// re compute?
repaint();
}
}
With this code I am able to resize the width, height of 3 tables.
container.addControlListener(new ControlAdapter() {
#Override
public void controlResized(ControlEvent e) {
tableJobs.setBounds(20, 143,container.getBounds().width-40, container.getBounds().height-20);
tableMessages.setBounds(20, 143,container.getBounds().width-40, container.getBounds().height-20);
tableSplfs.setBounds(20, 143,container.getBounds().width-40, container.getBounds().height-20);
}
});

Programmatically Generating Actionevent in Java

I'm making an App. in java , in which there is a Button to which I have added an actionlistener. The ActionEvent it(the button) generates executes some code. Now I want this piece of code to run whenever the app. starts and without pressing the button. I mean, I want to generate the Actionevent (without pressing the button) so that the piece of code the ActionPerformed contains gets executed as the app. start. After that, it may run whenever I press the button.
You can create ActionEvents like any other Java Object by just using the constructor. And then you can send them directly to the component with Component.processEvent(..)
However, in this case I think you are better making your code into a separate function which is called both:
By the ActionListener when the button is pressed
Directly by your application startup code (possibility using SwingUtilities.invokeLater() or SwingUtilities.invokeAndWait() if you need it to happen on the event-handling thread)
This way you don't mix up presentation logic with the business logic of whatever the code does....
Yes it can be done, but it doesn't really make sense, since your goal isn't to press a button or to call an ActionListener's code, but rather to have a common behavior on button press and on program start up. To me the best way to achieve this is to have a method that is called by both the actionPerformed method of the ActionListener and by the class at start up.
Here's a simple example. In the code below, a method disables a button, turns the JPanel green, and starts a Timer that in 2 seconds enables the button and resets the JPanel's background color to its default. The method that causes this behavior is called both in the main class's constructor and in the JButton's ActionListener's actionPerformed method:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ActionOnStartUp extends JPanel {
private static final int PANEL_W = 400;
private static final int PANEL_H = 300;
private static final int TIMER_DELAY = 2000;
private JButton turnGreenBtn = new JButton("Turn Panel Green for 2 seconds");;
public ActionOnStartUp() {
turnPanelGreen();
turnGreenBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
turnPanelGreen();
}
});
add(turnGreenBtn);
}
public void turnPanelGreen() {
setBackground(Color.green);
turnGreenBtn.setEnabled(false);
new Timer(TIMER_DELAY, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
setBackground(null);
turnGreenBtn.setEnabled(true);
((Timer) ae.getSource()).stop(); // stop the Timer
}
}).start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PANEL_W, PANEL_H);
}
public static void createAndShowGui() {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ActionOnStartUp());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Usually, the button action event responds to an external event, to notify the application that the user (or rather something or someone) interacted with the application. If your button executes some code that you want to also execute at application start, why not just place everything at it's proper place?
Example:
public class SomeSharedObject {
public void executeSomeCode() { /*....*/ }
}
Set the button with something like
public void setButtonAction(final SOmeSharedObject obj) {
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
obj.executeSomeCode();
}
});
}
And run at application start with something like
public void initApplication(SomeSharedObject obj) {
obj.executeSomeCode();
}
And, if the code you need to execute takes a while to complete, you might want to use a separate thread inside your actionPerformed button event so your application UI does not freeze up.
Just Call JButton.doClick() it should fire the ActionEvent associated with the JButton.

Categories

Resources