I know how to do action listeners for button clicks in/on swing, but I have this class which does some stuff but I want it a function/event that when a button is clicked it runs a method similiar to the PaintComponent below... (draws a line)
class CustomPanel extends JPanel {
private int destx = 100;
private int desty = 100;
private int startx = 0;
private int starty = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(startx, starty, destx, desty);
}
}
How would I call this paintcomponent (Or a similar one which draws a line) from a action listener?
Here is my actionlistener: (Its on GUI.java while the code above is on CustomPanel.java)
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == loginButton)
{
//Does other stuff but removed for simplifying
CustomPanel cp = new CustomPanel();
}
}
Thanks alot,
Your question didn't make sense to me in your last posting and it still doesn't make sense to me in this posting.
You still haven't posted a SSCCE that attempts to demonstrate what you want to do.
If you have a "login panel", typically that is done by creating a modal JDialog.
If you are trying to draw a diagonal across the top of all components in the frame, then you would need to use a Glass Pane or a Layered Pane.
Read the section from the Swing tutorial on How to Use Root Panes for examples and more detailed information.
You need to add it to gui. Something like this:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
parentPanel.add(new CustomPanel());
parentPanel.revalidate();
parentPanel.repaint();
}
});
But if you only want to draw a line on the current container that's another thing...
Simply adding your CustomPanel to any other JComponent and updating the UI should do the trick. Swing takes care of all the painting for you.
Here is a reslly useful guide to swing painting;
http://java.sun.com/products/jfc/tsc/articles/painting/#paint_process
Related
I have a data plot with a color bar that's a JPanel with a layout that has two JPanels inside of it. One JPanel is the data plot itself, and the other is the color bar. I'd like to add functionality so the color bar can be toggled on and off, and I've gone about this by simply removing the JPanel containing the color bar. Something like this:
public class Data2DPlotWithColorBar extends JPanel {
public Data2DPlotWithColorBar() {
this.data2DPlot = new Data2DPlot();
this.colorBar = new VerticalColorBar();
this.setPlot();
}
public final void toggleColorBar() {
enableColorBar = !enableColorBar;
setPlot();
}
private void setPlot() {
this.removeAll();
this.setLayout(new BorderLayout());
if (enableColorBar) {
this.add(colorBar, BorderLayout.EAST);
}
this.add(this.data2DPlot, BorderLayout.CENTER);
this.revalidate();
this.repaint();
}
private final Data2DPlot data2DPlot;
private final VerticalColorBar colorBar;
private boolean enableColorBar;
}
The problem is that when the color bar is removed, the data plot has a component listener with the componentResized method overrided which correctly resizes the data (maintains fixed aspect ratio) to fit the size of the JPanel. Something like this:
public class Data2DPlot extends JPanel {
...
#Override
public final void componentResized(ComponentEvent e) {
double scaleFactorBuf = Math.min((double)getPixelMaxViewWidth()/getNativeWidth(),
(double)getPixelMaxViewHeight()/getNativeHeight());
// Make sure scaleFactorBuf isn't close to zero
if (Math.abs(scaleFactorBuf) > MathUtilities.LAMBDA) {
scaleFactor = scaleFactorBuf;
}
}
...
#Override
protected final void paintComponent(Graphics g) {
super.paintComponent(g);
....
}
}
It turns out that as-is, the dataplot is not resizing properly. I did some debugging and I found out that componentResized gets called AFTER the paintComponent method when I toggle the color bar off and on. This means the image gets painted, and then the scaleFactor gets updated afterwards, which is incorrect. The only way I've been able to fix it so far is to call repaint() at the very end of the componentResized method. However, repaint() is already called when the component is resized, so I feel like this is the incorrect approach. Some googled led me to solutions involving the use of revalidate and repaint after modifying a JPanel on demand. However, any combination of doing this still led to componentResized being called after repaint. Is there a standard fix for this?
An answer proposed in this thread offers an easy solution; rather than overriding the componentResized method, do the setBounds(int,int,int,int) one.
The call order of componentResized, setBounds, and repaint is strange; on program startup it is like this;
setBounds
componentResized
repaint
while if you manually resize it later (I did not test with in-code resizing order) it goes
setBounds
repaint
componentResized
By setting your flags in setBounds rather than componentResized, you can know to recompute your repaint size-sensitive variables on panel resizing, effective immediately.
I'm attempting to code a simple animation or physics example in a Java Swing application. I have the actual windows application open and working, but I can't figure out how to actually draw my shapes, and how I'd format the code for calculations between frames, that sort of stuff.
I've read some stuff about over riding a paint method, but I don't know what that means, and I don't believe I'm using it in the code I'm using right now. This is my code:
public class Physics extends JFrame{
public Physics() {
initUI();
}
private void initUI() {
JPanel panel = new JPanel();
getContentPane().add(panel);
panel.setLayout(null);
final JLabel label = new JLabel("Hi, press the button to do something");
label.setBounds(20, 0, 2000, 60);
final JButton submitButton = new JButton("Start");
submitButton.setBounds(20, 150, 80, 20);
submitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Put button code here later
}
});
panel.add(label);
panel.add(submitButton);
setTitle("Program");
setSize(300, 250);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Physics ex = new Physics();
ex.setVisible(true);
}
});
}
}
So I have some blank space above my button where I'd like to draw maybe a square or circle moving across the screen to start off with, once I get that down I can start getting into the more advanced stuff. Any hints on how to do that would be appriciated :D
Thanks!
"I've read some stuff about over riding a paint method, but I don't know what that means"
So you've overridden actionPerformed, so you know what an #Override is. As you'll notice from the ActionListener, you never actually explicitly call actionPerformed, but whatever you put in the there, still get's used. That's because the ActionListener implicitly call it for you.
The same is true with painting. In the Swing painting process, there is a paint chain that Swing uses to paint components. Along the way paint is called somewhere. So just like actionPerformed, you can override paint and it will get implicitly called for you.
#Override
public void paint(Graphics g) {
super.paint(g);
}
The Graphics object passed to the method is the graphics context that Swing will use for the painting. You can look at the Graphics API to see the methods you can use. You can use drawOval to draw a circle
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawOval(x, y, width, height);
}
Now here's the thing. You don't actually want to override paint. In the tutorials linked above, some of the examples will use applets and override paint, but you shouldn'y paint on top level containers like JFrame or JApplet. Instead paint on a JPanel or JComponent and just add it the JFrame. When you do paint on JPanel or JComponent, you'll instead override paintComponent (which also gets called along the paint chain), instead of paint
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, width, height);
}
You see how I used variables for the drawOval method. The x is the x location from the top-let of the screen, and y and the y point. width and height are width and height of the circle. The great thing about using variables is that their values can be changed at runtime.
That's where the animation comes to play. As pointed out, you an use a javax.swing.Timer
The basic construct is
public Timer(int delay, ActionListener listener) {
}
The delay is the milliseconds to delay each call to the listener. The listener will have your actionPerformed call back that will do what's inside, every delay milliseconds. So what you can do, is just change the x from the drawOval and repaint(), and it will animate. Something like
Timer timer = new Timer(40, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
x += 5;
repaint();
}
});
timer.start();
The timer code you can just put in the constructor. That's probably simplest explanation I can give. Hope it helps.
Don't forget the to see Custom Painting and Grapics2D for more advance topics on graphics. Also see some example of timers and animation here and here and here and here and here
Also avoid using null layouts. See Laying out Components Within a Container to learn how to use layout managers, as should be done with Swing apps.
Take a look at the Swing tutorial on Custom Painting.
The example shows you how to do painting. If you want animation, then you would use a Swing Timer to schedule the animation. The tutorial also has a section on How to use a Swing Timer.
Put the two tutorial together and you have a solution.
There are any number of ways to achieve this.
Start by taking a look at:
Performing Custom Painting
2D Graphics
For details about how painting in Swing is done.
Animation is not as simple as just pausing a small period of time and then repainting, theres acceleration and deceleration and other concepts that need to be considered.
While you could write your own, that's not a small task, a better solution might be to use a pre-existing engine, for example...
Then take a look at:
Timing Framework
Trident
java-universal-tween-engine
Which are all examples of animation engines in Swing. While I prefer the Timing Framework as it provides me with a lower level API, this is a personal opinion. Both Trident and the JUWE seem to be geared more towards component/property based animation (which the Timing Framework can do if you want to build some of the feature sets up)
I created a simple animation with two rockets blasting off. The full eclipse project is here: https://github.com/CoachEd/JavaExamples/tree/master/RaceToSpace. Here's a screenshot:
Recently, I have been trying to make my gui's look good and part of it is implementing my own titlebar, maximize button, minimize button, etc.
I am having issues on the dragging, I want to be able to drag the JFrame by clicking anywhere in it.
I attempted to create a mousemotionlistener to handle it however it slips when I use it. As in I attempt to drag the window to a location however it appears to be skipping calls to mouseDragged and attempting to call mouseMoved instead.
Here is my code
public class MouseWindowDragManager implements MouseMotionListener{
private JFrame frame;
int prevPosX = -1;
int prevPosY = -1;
public MouseWindowDragManager(JFrame frame){
this.frame = frame;
}
#Override
public void mouseDragged(MouseEvent e) {
int newX = (frame.getLocation().x + (e.getXOnScreen() - prevPosX));
int newY = (frame.getLocation().y + (e.getYOnScreen() - prevPosY));
frame.setLocation(newX, newY);
prevPosX = e.getXOnScreen();
prevPosY = e.getYOnScreen();
}
#Override
public void mouseMoved(MouseEvent e) {
prevPosX = e.getXOnScreen();
prevPosY = e.getProperty("apple.awt.draggableWindowBackground", true);tYOnScreen();
}
}
Recently, I have been trying to make my gui's look good and part of it is implementing my own titlebar, maximize button, minimize button, etc.
Gee, Microsoft and Apple spend millions of dollars to develop GUI's that users can use. They will be disappointed to hear this :)
I want to be able to drag the JFrame by clicking anywhere in it.
Check out Moving Windows for a class that allows you to drag a window around. The example code shows how to use the class by just dragging on your custom title bar. However, if you really want to be able to drag the frame by clicking anywhere then you can register the frame's root pane with the ComponentMover.
Okay, so in this program I'm making, users will be able to create shortcuts to their favorite apps on their computer. My program will be kind of like a hub, I guess, for apps. I have a small problem though, which involves two classes: AppButton and AppButtonContainer. They both implement MouseListener, but AppButton extends JComponent and AppButtonContainer extends JPanel. Basically, when an AppButton is clicked, it sets a draws the border in a different color to make it look selected. Otherwise, it sets the border to the background color. When you double click it, it opens up the application specified. I have a method in AppButton to remove the focus, and therefore setting the border to the background color. In AppButtonContainer, there is a bit of code so that when, the panel is clicked, it removes the focus from the AppButton.
That's my problem, though. The AppButtonContainer doesn't realize that it's clicked. I'm thinking it has something to do with top level containers or something, but I'm not sure. Can anybody help?
EDIT: I found out that I didn't put the addMouseListener(this) in the constructor of the AppButtonContainer. Thank you for everyone who helped me clear up this problem and give me tips along the way :)
AppButtonContianer:
public class AppButtonContainer extends JPanel implements MouseListener {
private static final long serialVersionUID = 6485231881729120957L;
public List<AppButton> appButtons;
private static final Color BACKGROUND_COLOR = new Color(18, 18, 18);
public AppButtonContainer(List<AppButton> buttons) {
this.appButtons = buttons;
setLayout(new GridLayout(5, 5, 20, 20));
addButtonsToPane();
}
private void addButtonsToPane() {
List<AppButton> buttons = this.appButtons;
for (int i = 0; i < buttons.size(); i++) {
this.add(buttons.get(i));
}
}
private void removeAllButtonFocus() {
for (int i = 0; i < this.appButtons.size(); i++) {
this.appButtons.get(i).removeFocus();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(BACKGROUND_COLOR);
repaint();
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Pane Clicked");
removeAllButtonFocus();
}
...Other MouseEvent methods
You can solve the problem at hand by putting addMouseListener(this) in the constructor for your AppButtonContainer class. Otherwise, it'll never pick up mouse events.
Generally, though, it's not good to turn your classes into mouselisteners like that. Perhaps try making an inner class to listen for mouse events and pass them to the AppButtonContainer instead.
I'm super confused with what exactly models are supposed to do in java swing. At present I'm basically trying to create a model for JButton to detect if it isPressed(); My essential goal of the model is to do something like this:
if(myButton.isPressed() ) {
myButton.setBackground(Color.RED);
}
else{//when any other button is pressed?
myButton.setBackground(Color.WHITE);
}
At present my code is something like this:
numberButton = new JButton("Num");
numberButton.setBounds(20,40,80,30);
numberButton.addChangeListener(new ChangeListener() {
public void stateChanged (ChangeEvent e){
if (model.isPressed() ){
doColorChange(model);
}
}
});
I understand that this is totally wrong, but I have no idea where, and I haven't found a tutorial that really explains what I'm doing wrong or why I need a model for this at all.
Please help me restore my sanity! Thanks a lot!
Use radio buttons in a button group.
import java.awt.image.BufferedImage;
import java.awt.*;
import javax.swing.*;
import java.net.URL;
import javax.imageio.ImageIO;
class RedAndWhite {
public static Image getColoredImage(Color color, int size) {
BufferedImage bi = new BufferedImage(
size,
size,
BufferedImage.TYPE_INT_RGB);
Graphics g = bi.getGraphics();
g.setColor(color);
g.fillRect(0,0,size,size);
g.dispose();
return bi;
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Image red = getColoredImage(Color.RED, 32);
Image white = getColoredImage(Color.WHITE, 32);
JPanel p = new JPanel(new GridLayout(1,0,5,5));
ButtonGroup bg = new ButtonGroup();
for (int ii=0; ii<6; ii++) {
JRadioButton b = new JRadioButton();
b.setSelectedIcon(new ImageIcon(red));
b.setIcon(new ImageIcon(white));
b.setContentAreaFilled(true);
bg.add(b);
p.add(b);
}
JOptionPane.showMessageDialog(null, p);
}
});
}
}
I think what you want is register an ActionListener or Action with the button in order to handle button presses, right?
Edit: rereading your answer, it seems you want to highlight the button that is being pressed, right? In that case, try to use your own button ui (subclass the one of the look and feel you're using). BasicButtonUI has a method protected void paintButtonPressed(Graphics g, AbstractButton b) that you could override to apply the highlight when the button is being pressed.
there are follows ways how to make JButton nicer
1) most nicest way is painting only Borders from ButtonModel on Mouse events
2) override whole BasicButtonUI with all rellevant Look and Feels
3) put there Icons and override all possible methods implemented in JButton API
4) best at all would be implement Custom Look and Feel
5) create Custom JComponent based on JLabel/JComponent
I always took it that the ButtonModel is intended (mostly) for use by the UI class to render the button in its pressed/not-pressed/armed/selected/... state and track changes to that state.
If you simply want to paint the button red (that is waht you want?) while it is pressed your solution seems fine to me.
If you have a Toggle Button (that remains pressed after it has been clicked to indicate a "selected" state, you might want to use an ItemListener and check for
ItemEvent.ITEM_STATE_CHANGED == ItemEvent.SELECTED // paint red
ItemEvent.ITEM_STATE_CHANGED == ItemEvent.DESELECTED // paint white
If you want to execute application logic when the button is clicked, use an ActionListener.