I know that a similar question was posted before, but there was no answer or example code.
I need a transparent JPanel on top of a canvas. The code posted below is not working
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
public class Main {
private static class Background extends Canvas{
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.RED);
g.drawOval(10, 10, 20, 20);
}
}
private static class Transparent extends JPanel {
public Transparent() {
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.drawOval(20, 20, 20, 20);
}
}
public static void main(String[] args){
JFrame frame = new JFrame();
JLayeredPane layered = new JLayeredPane();
Background b = new Background();
Transparent t = new Transparent();
layered.setSize(200, 200);
b.setSize(200, 200);
t.setSize(200, 200);
layered.setLayout(new BorderLayout());
layered.add(b, BorderLayout.CENTER, 1);
layered.add(t, BorderLayout.CENTER, 0);
frame.setLayout(new BorderLayout());
frame.add(layered, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}
}
Using the GlassPane property of the entire frame is the very last solution (highly discouraged)
You probably will not be able to get this to work because you are mixing heavyweight and lightweight components together.
In the past it used to be impossible to draw lightweight panels over heavyweight components like a Canvas. Since JDK 6 Update 12 and JDK 7 build 19 Java has corrected this and you can overlap the 2 correctly however it comes with limitations. Specifically in your case the Overlapping swing component cannot be transparent.
A good description for this including the newer behaviour can be found on this page: Mixing Heavyweight and Lightweight Components Check the limitations section for your specific problem.
I don't think using the GlassPane will help as it is also lightweight.
If you change the BackGround class to extend JPanel instead of Canvas you will get the behaviour you want.
While AWT is limited it should not be too hard to implement something similar with AWT itself by extending either the Container or Component class.
Related
I am learning how to program a graphical user interface in Java. I pretty much know some basics but in this program, I am trying to draw onto a JFrame with a black background, but as soon as I run the program the JFrame only displays a white line on a white background. I would appreciate it very much if anyone knew how to fix this, I have been trying myself but I can't seem to figure it out.
Thanks for your attention. I’m looking forward to a reply.
public class test1 {
public static void main (String[] args)
{
JFrame frame = new JFrame();
frame.setSize(1835,1019);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setResizable(false);
frame.getContentPane().setBackground(Color.BLACK);
JPanel raum = new JPanel()
{
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.WHITE);
g2.drawLine(500,500,500,800);
}
};
frame.add(raum);
}
}
There a number of issues which are going to cause you endless amount of problems going into the future.
The obvious one is the fact that the background color of the panel is very close to WHITE, so it makes it very difficult to see the line. You could change the background color of the panel or the line and it should solve the immediate issue.
You really need to take a look at Performing Custom Painting and Painting in AWT and Swing to get a better understanding of how painting works in Swing.
It is generally recommended to override paintComponent and avoid overriding paint. paint does a lot work and unless you're willing to take over ALL it's workload, you're better off avoiding it.
As a general rule, you should also call the super.paintXxx method before you do any custom painting. Again, painting is generally a complex workflow, best to just let the parent class do its job.
A component should also provide sizing hints back to the parent container, the parent container can then make better decisions (via the LayoutManager) as to how all the components should be laid out. Because different platforms (and even same platforms with different settings) can generate different size window decorations, you're better off managing the size of the "content" over the size of the "window". Again, this is going to save you no end of headaches into the future.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
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() {
setBackground(Color.BLACK);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1080, 1920);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setPaint(Color.WHITE);
g2d.drawLine(500, 500, 500, 800);
g2d.dispose();
}
}
}
Im trying to add a JScrollpane to my JPanel. The problem is that the scrollpane doesn't recognize that my drawing is outside the frame. So how do I add the JScrollpane correctly?
Main class:
public MainFrame() extends JFrame{
public MainFrame() {
Container container = getContentPane();
container(new BorderLayout());
container.add(new JScrollPane(new Drawing()));
setSize(1280,720);
setVisible(true);
}
Drawing class:
public class Drawing() extends JPanel {
#Override
protected void paintComponent(Graphics g) {
g.drawLine(10, 100, 30000, 10);
}
}
There are a couple of errors in your code, let's step through each of them:
You're extending JFrame, and you should avoid it, see: Extends JFrame vs. creating it inside the program for more information about it. You're actually not changing its behavior so it's not needed to extend it.
For your JScrollPane to show the whole line, you need to change your window's size to be the same size of your line (as shown in this answer by #MadProgrammer).
Related to point 2, avoid the use of setSize(...) and instead override getPreferredSize(): See Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? for more information
You forgot to call super.paintComponent(...) method in your paintComponent() method.
Related to points 2, 3, you need to call pack() so Swing calculates the best preferred size for your component.
See this example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class LongDraw {
private JFrame frame;
private Drawing drawing;
public static void main(String[] args) {
SwingUtilities.invokeLater(new LongDraw()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
drawing = new Drawing();
JScrollPane scroll = new JScrollPane(drawing);
frame.add(scroll);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class Drawing extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawLine(10, 100, 3000, 10);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(3000, 500);
}
}
}
Which produces something similar to this:
I'm building a GUI for a data processing algorithm. I can instantiate the window, give it a background, title, etc., but when I try adding panels to it, I run into trouble. What I'm really looking for more than a proofreader is a suggestion for the sequence in which to build, configure, and add objects in Java Swing so that they behave correctly, in a generic sense. So, is this the best way to build a JFrame with a different-colored panel in it?
Declare JFrame
Set JFrame color (background color)
Declare JPanel (box to represent data graphically)
Set JPanel color (box color)
Add JPanel to JFrame
Set JFrame to visible = true
It makes sense intuitively but it doesn't seem to work, no matter what I do. I've found step-by-step instructions elsewhere but they tend to explain what to type more than why you're typing it, so you get a very narrow understanding of what's going on. Thanks for any help!
Below is the full code; I hesitated to post it because I'd begun experimenting with Graphics2D and it isn't well-commented, but if it helps:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.*;
import javax.swing.border.TitledBorder;
public class GUI extends JFrame
{
JFrame mainWindow = new JFrame();
JPanel backgroundPanel = new JPanel();
JPanel subPanel = new JPanel();
Color background = new Color(40,40,40);
Color subWindow = new Color(255, 255, 255);
TitledBorder title = BorderFactory.createTitledBorder("title");
Rectangle rect1 = new Rectangle(10, 10, 40, 40);
Graphics2D g;
public static void main (String[] args)
{
new GUI();
}
public GUI()
{
initializeGUI();
}
private void initializeGUI()
{
mainWindow.setSize(1340, 880);
backgroundPanel.setBackground(background);
subPanel.setBackground(subWindow);
subPanel.setBorder(title);
mainWindow.setTitle("Ed");
mainWindow.setLocationRelativeTo(null);
mainWindow.setDefaultCloseOperation(EXIT_ON_CLOSE);
mainWindow.add(backgroundPanel);
backgroundPanel.add(subPanel);
updateGUI();
}
public void updateGUI()
{
mainWindow.setVisible(false);
mainWindow.setVisible(true);
}
public void paintComponent(Graphics g)
{
this.g.setColor(subWindow);
this.g.fill(rect1);
this.g = (Graphics2D) g;
}
}
Let's break this down....
public class GUI extends JFrame {
JFrame mainWindow = new JFrame();
There is no need to extend from JFrame as you are neither using it nor are you adding any value to the class.
This...
public void paintComponent(Graphics g) {
this.g.setColor(subWindow);
this.g.fill(rect1);
this.g = (Graphics2D) g;
}
is doing nothing and will never be called, as nothing you've extended from implements a paintComponent method (that is, JFrame does not have a paintComponent methd) (and you class is not attached to anything displayed on the screen anyway). Also, you should NEVER maintain a reference to ANY Graphics context you did not create yourself.
The reason that subPanel is appearing so "small" is because it has not definable size, aside from the border.
You could rectify this in one of three ways...
You could change the layout manager of backgroundPanel to something like BorderLayout
You could override the getPreferredSize method of the subPanel to return a more suitable size or
You could add other components to it and let the layout manager figure it out...
In any case, you should have a look at Laying Out Components Within a Container.
You should also have a look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting is done in Swing
I decided to write a small Java program to experiment around with BorderLayout, because I'm developing a Java game and I need to have 2 objects placed in a single JFrame at the same time, and everyone I asked said I need BorderLayout to do that.
So the Java program I wrote is supposed to place a JButton on the JFrame and ALSO place a graphic component (a rectangle in this case). The problem is, only the button shows up, as can be seen in the image link below:
http://prntscr.com/3m5ek6
I can't post actual images due to my low reputation statistic.
Here is the code:
main.java --> The main method class + JFrame/JPanel/JButton constructor
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class main {
public static void main(String[] args) {
Infout m = new Infout();
JFrame f = new JFrame();
JPanel start = new JPanel();
JPanel start2 = new JPanel();
start.add(m);
start2.add(new JButton("Hi"));
f.add(start,BorderLayout.LINE_START);
f.add(start2, BorderLayout.LINE_END);
f.setVisible(true);
f.setSize(300, 400);
}
}
Infout.java --> Rectangle constructor class
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
public class Infout extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Rectangle2D.Double(140, 270, 5, 300));
}
}
Can someone tell me what's wrong? Also, is using BorderLayout the best option for adding multiple static and/or dynamic objects to a JFrame?
Thanks!
Ab
You need to override the getPreferredSize() method so the layout manager can determine the proper size for the component.
How do I do that?
Read the section from the Swing tutorial on Custom Painting for more information on custom painting, including a working example that shows how to override the getPreferredSize() method.
I have a JFrame that I am putting several JButtons on. Half the JButtons have color coding--i.e. I turn them blue when X event happens--and I use btn.setBackgroundColor(Color). When I use setBackgroundColor, I can see that I look the ones that are normal JButtons have shading/coloring/something that the ones with the setBackgroundColor do not. I've tried making the color transparent to a limited degree, but I still get a flat block of color, rather than a tinted version of the shaded button.
This seems like it should be a pretty easy thing to fix, but it is bugging me right now. I don't want to change the default LAF--it's fine. I don't want to abandon the color change. I do want the buttons to all appear styled (the word I'd use for HTML).
So I'm missing something right here....what is it?
Edited to add:
JFrame frame = new JFrame();
frame.add(new JButton("42"));
JButton btn24 = new JButton("24");
btn24.setBackground(Color.red);
frame.add(btn24);
frame.setVisible(true);
In the above example, "42" will--on my Windows machine--show a slight color variation at the bottom and the top, creating a rounded and shaded effect. The "24" button will show a red square. My question is: Is there a way to make "24" show the rounded/shaded/styled with the red tint on top? Or do I need to simple make all my buttons flat squares for a uniform appearance?
Thanks!
Create a custom JButton and override the paint method as illustrated bellow :
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
JButton btn24 = new DepthButton("24");
JButton btn25 = new DepthButton("25");
btn24.setBackground(Color.red);
btn25.setBackground(Color.GREEN);
JPanel pane = new JPanel(new BorderLayout());
pane.add(new JButton("42"), BorderLayout.PAGE_START);
pane.add(btn24, BorderLayout.PAGE_END);
pane.add(btn25, BorderLayout.CENTER);
frame.add(pane);
frame.pack();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setVisible(true);
}
/**
*
* #author Romain Guy
*/
public static class DepthButton extends JButton {
/** Creates a new instance of DepthButton */
public DepthButton(String text) {
super(text);
setContentAreaFilled(false);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
GradientPaint p;
p = new GradientPaint(0, 0, new Color(0xFFFFFF), 0, getHeight(), getBackground());
Paint oldPaint = g2.getPaint();
g2.setPaint(p);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setPaint(oldPaint);
super.paintComponent(g);
}
}
}
And Here is the Result:
The example is from an excellent book for advanced java swing : Filthy Rich Clients
https://github.com/romainguy/filthy-rich-clients/blob/master/Gradients/TwoStopsGradient/src/DepthButton.java