I have a quite simple question about laying out components in Java AWT program here.
What I want to achieve is, to set the background of the application to a specified image (from file systenm) and add a button on the UI.
What I have is
package javaapplication2;
import java.awt.*;
import java.awt.Container;
import java.awt.Color;
import java.awt.Font;
import java.awt.Button;
import java.util.HashSet;
public class JavaApplication2 extends Frame {
private Container gui;
private Button b;
public JavaApplication2() {
setSize(400,400); // set size to 400x400
gui = new Container() { // my own container that may write string (or draw image in the future)
public void paint(Graphics g) {
super.paint(g);
g.setFont(new Font(null, Font.PLAIN, 48));
g.setColor(new Color(10,10,10));
g.fillRect(20, 20, getWidth()-40, getHeight()-40);
g.setColor(new Color(24, 89, 245));
g.drawString("hello", 200,200);
}
};
// create a button
b = new Button("bu");
// add the button into the container?
gui.add(b);
b.setVisible(true);
// add gui into the root container
add(gui);
gui.setSize(400, 400);
//gui.setVisible(true);
validate();
}
public static void main(String[] args) {
// TODO code application logic heren
JavaApplication2 a = new JavaApplication2();
a.setVisible(true);
}
}
Then when I ran it, all I could see is black background (color(10,10,10)) and text "hello". I guess that's because although b is added into the container, the paint is called so the whole container is painted so I can't see the button.
I guess there should be some simple solution and hope someone can help me with it.
Related
I'm new to Java and as such I've been doing my own small projects to help my learning. The code below when run will launch a new window where I changed the colour background which is correct, but the text doesn't appear and I don't understand why as there are no error messages.
In trying to fix this I tried it as an applet instead of a frame but that failed to work due to an error with a missing class. My guess is I'm missing something here but I don't know what.
Any help appreciated
import java.awt.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
public class Fonts extends Frame
{
public void paint(Graphics g)
{
setBackground(Color.blue);
g.setColor(Color.white);
Font quote = new Font("TimesRoman", Font.PLAIN, 30);
g.setFont(quote);
g.drawString("Hello World ", 10, 10);
}
public static void main (String args[])
{
Frame ff = new Fonts();
ff.resize(500,500);
ff.show();
}
}
I've made a JFrame with Diferent JButtons and i'd like to get an image from another class. Any ideas? Or how draw on the same class but on the action performed?
Because it doesnt let me to do any drawings...my complier always gives me error messages
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.*;
public class red extends JFrame {
public JButton b;
public JButton b1;
public JButton b2;
public JButton b3;
public JButton b4;
public static Image p;
public static Graphics g;
public red() throws IOException {
gui1 x = new gui1();
setTitle(" ");
setSize(1200,700);
setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
b= new JButton("click");
b1= new JButton();
b.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e0){
b1.setBounds(0, 0, 200, 200);
b.show(false);
add(x);
}
});
b.setBounds(0, 0, 100, 100);
add(b1);
add(b);
setVisible(true);
}
public static void main(String[] args) throws IOException {
red k = new red();
}
}
import java.awt.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class gui1 extends Canvas {
public static Image p;
public void paint(Graphics g){
g.drawImage(p, 700, 200, 100, 100, this);
}
{
try {
p= ImageIO.read(new File("Lighthouse.jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Phew! I see A LOT of errors in your code (even after I corrected the compilation errors):
You're not following the Java naming conventions:
Class names should be nouns, in mixed case with the first letter of each internal word capitalized
while red is a noun it should be more descriptive and be capitalized. The same goes for gui1
You're extending JFrame which in plain english would say: red is a JFrame, you should really avoid this and create your GUI based on JPanels instead... see Java Swing using extends JFrame vs callint it inside of class
You're setting size (a REAAAAAAALLY big one window for the JButton sizes you're using), instead use pack()
You're using null-layout, while pixel-perfect GUIs might seem like the easiest way to create complex GUIs for Swing newbies, the more you use them the more problems related to this you'll find in the future, they are hard to maintain and cause random problems, they don't resize, etc. Please read Null layout is evil and Why is it frowned upon to use a null layout in Swing? for more information about why you should avoid its use and why you should change your GUI to work with Layout Managers along with Empty Borders for extra spacing between components.
You're making use of a deprecated method JFrame#show() you should be using JFrame#setVisible(...) instead.
Related to point #4, you shouldn't be calling setBounds(...) method, but let that calculations to the layout managers.
You're not placing your program on the Event Dispatch Thread (EDT), Swing is not thread safe, you can fix this by changing your main() method as follows:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//Your constructor here
}
});
}
You're mixing AWT and Swing components, instead of using AWT's Canvas use Swing's JPanel which has more functionality and support.
Images will become embedded resources once they're packaged in a JAR file, so it's wise to start treating them as if they already were, not as external files as shown in the embedded-resource tag.
Once you change from Canvas to JPanel you should override its paintComponent(...) method and not paint(...) and call it's super.paintComponent(g) method as the first line, also don't forget to add the #Overrides annotation. See the tutorial on Swing custom painting.
You're abusing the use of static keyword, see how does the static keyword works?
After seeing all the above errors I recommend you to go back and Learn the basics of the language before starting with a graphical environment which will only add more difficulty to your learning.
From what I understand you want to draw an image on a button click, if that's the case then you can wrap your image in a JLabel and add that JLabel to a JPanel which then is added to a parent JPanel which is later added to the JFrame:
As you can see in the GIF above, the icon is displayed after user presses the button.
Obviously this can be improved for the GUI to be more "attractive" with combinations of layout managers and empty borders as stated before.
This was done with the following code:
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ImageDrawingFromOneClassToAnother {
private JFrame frame;
private JPanel pane;
private JPanel leftPane;
private JPanel rightPane;
private ImageIcon icon;
private JButton button;
private JLabel label;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ImageDrawingFromOneClassToAnother().createAndShowGui();
}
});
}
public void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
icon = new ImageIcon(this.getClass().getResource("king.png")); //Read images as if they were already embedded resources
button = new JButton("Draw image");
label = new JLabel(""); //Create an empty label
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setIcon(icon); //On button click, we set the icon for the empty label
}
});
pane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200); //Set a size for the main panel
}
};
pane.setLayout(new GridLayout(1, 2)); //The main panel
leftPane = new JPanel(); //The button panel
leftPane.setLayout(new BoxLayout(leftPane, BoxLayout.PAGE_AXIS));
leftPane.add(button);
rightPane = new JPanel(); //The panel where the image will be drawn
rightPane.add(label);
//We add both (button and image) panels to the main panel
pane.add(leftPane);
pane.add(rightPane);
frame.add(pane); //Add the main panel to the frame
frame.pack(); //Calculate its preferred size
frame.setVisible(true); //Set it to be visible
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I was trying to use XOR mode in Graphics to draw a 1bit texture in color against a flat background, when I encountered a behaviour in Graphics I don't understand.
Here is an example of what I mean, isolated:
package teststuff;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class XORTest extends JFrame {
public XORTest() {
super("Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 400);
setIgnoreRepaint(true);
setResizable(false);
setVisible(true);
createBufferStrategy(2);
Graphics graphics = getBufferStrategy().getDrawGraphics();
graphics.setColor(Color.black);
graphics.fillRect(0, 0, getWidth(), getHeight());
graphics.setColor(Color.green);
graphics.fillRect(30, 40, 100, 200);
graphics.setXORMode(Color.white); // (*)
graphics.fillRect(60, 80, 100, 200);
graphics.dispose();
getBufferStrategy().show();
}
public static void main(String[] args) {
XORTest test = new XORTest();
}
}
If I uncomment the line marked with (*), two green rectangles are drawn as expected. If I leave it, nothing is drawn into the component, not even the black background or green rectangle that is drawn beforehand. Even more odd, it worked once. I had the color as Color.green instead of white before. After I changed it, it drew as expected. But when I closed the application and started it again, it didn't work anymore and it hasn't since.
Is this a bug in java? In my jre? Undocumented behaviour for Graphics? I'm on Windows and running the example on the jdk7.
Screenshots: Imgur album because it won't let me post 3 links
The third screenshot is the code as it is above, the first with (*) commented and the second is how it looked the one time it worked (I created that in GIMP because I didn't take a screenshot then).
Without a compelling reason to the contrary, it's easier and more reliable to override paintComponent() in JPanel, which is double buffered by default. With a compelling reason, follow the guidelines in BufferStrategy and BufferCapabilities. Also note,
Override getPreferredSize() to specify the preferred size of a component.
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* #see https://stackoverflow.com/a/16721780/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new XORPanel());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class XORPanel extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(190, 320);
}
#Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
graphics.setColor(Color.black);
graphics.fillRect(0, 0, getWidth(), getHeight());
graphics.setColor(Color.green);
graphics.fillRect(30, 40, 100, 200);
graphics.setXORMode(Color.white);
graphics.fillRect(60, 80, 100, 200);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}
I was wondering how you would get the color of the inset of a JTabbedPane. I cannot seem to get this color. Every attempt I make I get 236,236,236 which is the outside frame color, where the inside frame color is about 10 darker, 227,227,227 (using the built in apple color meter).
I am setting the look and feel using UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
You can see this in an image that I found on the internet. http://pagesofinterest.net/wordpress/wp-content/uploads/2009/06/Quaqua-Maven-Netbeans.jpg Where the words "Panel's Title" is the area that I am getting the lighter color that is not useful to me. Inside the round corners is the darker color I am trying to obtain. I tried getting the color of the content pane to no avail.
Thanks for all your help!
**EDIT:**Added code! As you see, I am trying to get the color of the area inside the rounded corners(if your on a mac) not the color of the frame or the tabs that say "1" "2". I have attached a photo and I am trying to get the background color of the portion that says "Here" Thanks!
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
public class main {
JFrame frame;
Container c1 = new Container();
Container c2 = new Container();
JTabbedPane top = new JTabbedPane();
static main GUI;
public void createGUI(){
frame = new JFrame();
Container c = frame.getContentPane();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
top = new JTabbedPane(JTabbedPane.TOP);
top.setFocusTraversalKeysEnabled(false);
top.setFocusable(false);
top.addTab("1", c1);
top.addTab("2", c2);
frame.setSize(315,450);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setResizable(true);
c.add(top);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {}
GUI = new main();
GUI.createGUI();
}
}
EDIT: camickr, Here is a screenshot of the UIManager Defaults. Unfortunately none of there colors in the are the correct color that the inset is.
You might be able to use UIMangaer Defaults to find the color.
You can override paintComponent() to use a GradientPaint in the tab's background, as shown below. A few notes,
Let the content adopt the preferred size of it contents, as shown here.
Construct the GUI in the event dispatch thread.
Use conventional Java names.
Addendum: the elements are not always in the same spot, so I do not know what place to get the color.
It sounds like you want to match a color used internally by the TabbedPaneUI delegate. One approach would be as follows:
Render a BufferedImage of the component, as shown here.
Determine the coordinates of a Point in top relative to the top of c1.
Point p = SwingUtilities.convertPoint(c1, 0, -1, top);
Obtain the color using getRGB(), as shown here; use Zoom to verify the result.
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
/** #see https://stackoverflow.com/a/16625260/230513 */
public class Main {
JFrame frame;
Container c1 = new GradientPanel();
Container c2 = new GradientPanel();
JTabbedPane top = new JTabbedPane();
private static class GradientPanel extends JPanel {
public GradientPanel() {
this.add(new JLabel("Here"));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
GradientPaint p = new GradientPaint(0, 0, Color.white,
getWidth(), getHeight(), Color.gray);
g2d.setPaint(p);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
public void createGUI() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
top = new JTabbedPane(JTabbedPane.TOP);
top.addTab("1", c1);
top.addTab("2", c2);
frame.add(top);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Main().createGUI();
}
});
}
}
When I add Swing component (like a JButton) to a JPanel, it renders with it's 'preferred size'.
However, the preferred size is actually larger than the painted button. There appears to be an invisible border around it.
Here's a simple frame with my test panel:
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TestPanel pnl = new TestPanel();
frame.getContentPane().add(pnl);
frame.pack();
frame.setVisible(true);
Here's my test panel ...
public class TestPanel extends JPanel {
JButton btn1 = new JButton("Test1");
JButton btn2 = new JButton("Test2");
public TestPanel() {
this.add(btn1);
this.add(btn2);
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.RED);
Dimension dim = btn1.getPreferredSize();
g.drawRect(btn1.getX(), btn1.getY(), (int)(dim.getWidth()), (int)(dim.getHeight()));
}
}
Notice I painted btn1's "PreferredSize" in RED to demonstrate that the preferredSize is actually larger than the button itself.
My question is, how can I determine the width and height of the painted button, not the JButton's preferredSize?
Any help is greatly appreciated, thanks!
UPDATE
Because I actually need this to work for all Swing components, here's a screen shot with the more components.
Unfortunately, I need to figure this out, determining the "real" size of the visible widget is crucial to my application.
I don't think this is particular or practically achievable.
The problem is, the button is using the "unpainted" area to paint other elements, like the focus highlight.
You could try look at the AbstractButton#set/getMargin
If nothing better comes along, note that the authors "recommend that you put the component in a JPanel and set the border on the JPanel."
Addendum: Based on your comments below, it's clear that your question is not about rendering borders but about establishing a component's boundary. What you perceive as unused space is actually reserved by the UI delegate for any number of uses, e.g. selection highlighting or esthetic coherence. You can get an idea of how this varies by selecting different Look & Feel themes in the examples here and here.
Using getbounds():
Using setBorder():
import component.Laf;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* #see https://stackoverflow.com/a/15490187/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new FlowLayout());
// https://stackoverflow.com/a/11949899/230513
f.add(Laf.createToolBar(f));
f.add(decorate(new JButton("Test")));
f.add(decorate(new JTextField("Test")));
f.add(decorate(new JTextArea(3, 8)));
f.add(decorate(new JCheckBox("Test")));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JPanel decorate(final JComponent c) {
JPanel p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle r = c.getBounds();
g.setColor(Color.red);
// NB pen hangs down and to the right
g.drawRect(r.x - 1, r.y - 1, r.width + 1, r.height + 1);
}
};
p.add(c);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}