I know this question has been asked a million times, and can be done by overriding paintComponent(), but what I want to know is how to change the shape while respecting the current Look And Feel. If I want to change the shape to a circle, I also want the button to look like a button, just with a different shape.
I tried making a JButton, the overriding paintComponent, then clipping it to a circle, but I didn't get the border effects on Nimbus LAF.
Is there a better way? Or is there a method in JButton?
For drawing components a ComponentUI is used. This UI class has a paint method and is used to paint the component. The paint method uses the settings of the L&F which are stored as properties in the UIManager.
To create your own component RoundButton extending from e.g. AbstractButton you can create your own RoundButtonUI (maybe extending from ButtonUI). Here you can create your own paint method using the properties of a normal button like Button.font or Button.foreground to draw your own component with the same L&F values as a normal button.
In your RoundButton class you should implement the method getUIClassID() which will return the string "RoundButtonUI". This causes your RoundButtonUI to be used.
A good example is JButton itself.
Related
I'm working on a project where I am displaying a square and a circle.
The circle moves on its own, but the user moves the square via the arrow keys. Whenever the circle touches the square, it rebounds.
Square and circle are different classes (2 different panels). I want to add those two to a frame, one on top of the other such that both are visible.
Can someone tell me how to do so?
JFrame n = new JFrame();
n.setTitle("Background Color for JFrame");
n.setSize(1000,600);
n.setLocationRelativeTo(null);
n.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
n.setResizable(false);
n.add(new Ball());
n.add(new Team());
n.setVisible(true);
User interface components at the same level in a hierarchy are assumed to be non-overlapping by default. You can explicitly work around this by making your components transparent with setOpaque(false), assuming you are taking care to only draw whats needed in the components, e.g. in case of a JPanel ensure that its background is not drawn. Its still somewhat random (implementation dependent) which component has precendence over another when doing this.
There is a component explicitly designed for that: JLayeredPane (https://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html), which manages "layers" in which components can be put, giving you full control which overlays which.
Games often implement this by themselves, since the full features of JComponent are not needed to represent a simple graphical element. In that case a single component is used as a "canvas" to paint self-defined objects onto making use of an override of paintComponent (See: https://docs.oracle.com/javase/tutorial/uiswing/painting/)
If you want to do this in swing, as it sounds, I would really recommend making a new class that extends JPanel, and override it's paintComponent method. In this method you use the Graphics in the argument to paint to the canvas. Then you can add this custom panel instead of two separate components to your JFrame, and handle the rendering in there. This render panel can then keep track of all objects that needs to be rendered, preferable implementing some interface (Drawable?) with a draw(Graphics g) method. That way you can make your classes that needs to be rendered implement your Drawable interface, keep then as a list in your render panel and just iterate through them in your paintComponent method and call draw on your Drawables.
Is there a way to change the default background painting of all instances of a swing component (a JPanel for example) to paint with a gradient background? Or would I need to create an extension of JPanel that paints with a gradient and then use that instead of JPanel everywhere in my app?
IMHO, it would be easier to just subclass the Swing component and override its paintComponent method to do the gradient painting. And then, as you said, use this custom component throughout the application.
It could be tricky using the UI properties since they may not be consistent across all LaFs.
It is not entirely clear what scope you intend. Did you mean by class (so all JPanel instances follow the new painting scheme), or do you mean all components in a Container (e.g. everything in Frame)?
There are possibilities to do this depending on component class, the places where you can hook into are the Look and Feel, and on a by component instance base, either the paintComponent() method, or if you need to replace the standard look of an existing component where you can not overwrite the method because you have no control over it, by providing your own UI class (look at Component.setUI) after the component has been created.
Except for the overwrite paintComponent approach neither is simple to implement. For most applications the simple approach is the best :)
I just looked a the source code from JSlider SourceCode
and if found a lot of repaint()'s as expected, because of the Template Pattern.
But my problem is i didn't find the paint method, which actually paints the JSlider.
Can anybody explain me how this component will be painted?
Swing components are typically painted by their associated UI class. The UI class is specific to each Look And Feel. This is how you get JSlider to have a "native" feel or even a custom feel on different platforms. Each Swing component has a UI class, JSlider has SliderUI which has several flavors such as: MetalSliderUI, WindowsSliderUI, and SynthSliderUI.
You didn't find a paint method in JSlider because the paint method is in the parent class, JComponent. JComponent's paint methods (paint, paintComponent, repaint, etc) do some setup but then delegates the work to the UI class, which is provided by JSlider. There is an entire method chain that takes place in Swing for correctly painting/sizing components.
If we knew what you were trying to do we might be able to help you out.
I ama drawing a rectangle in a panel and i added a + button to increase my shape's size.how can i do it?
Read the section from the Swing tutorial on Custom Painting for the basics.
Now, in your class that does the custom painting you need to keep two variables:
rectangleWidth
rectangleHeight
You will also need to add a method to the class like "increaseRectangleSize()". Then when you click your button you invoke that method. That method will increase the values of those two variables and then invoke repaint() on itself.
If you need more help post your SSCCE that demonstrates the problem since your description of the problem is too vague.
If your question is how to draw a bigger rectangle. In the paintComponent method that you are drawing a the rectangle increase the size. If you are trying to make the JPanel bigger, I would highly suggest you looking using Layout Managers and possibly set the PreferredSize() of the panel.
I have a simple GUI component written in Java. The class draws an analog clock in a java.awt.canvas.
This canvas is then contained in a JFrame - What I want to do is give the canvas a 3d "raised" effect - almost like adding a drop shadow to a photo.
Is there a simple way to do this?
If you are using a JFrame, then you have two options:
Add your own component to a JPanel first and then add this to the JFrame.
Instead of inheriting from java.awt.Canvas, you can inherit from JComponent. Then you would have to do all your painting in the paintComponent() Method instead of just paint() (you can just rename your current paint method).
In both cases you can now set a border with the setBorder() Method (on the JPanel or your component) you can get from BorderFactory.
See also: How to Use Borders
If you were using a Swing element, you'd use the createRaisedBevelBorder() method of the BorderFactory and set the canvas' border to the resulting border. Canvas is an AWT component, so you'll need to wrap it in a Swing component to which you can set the border.