Why is my Swing app not displaying properly? - java

I'm trying to come up with a Swing app that can display all available fonts and show me how they look :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Demo_Fonts extends JPanel
{
static String[] font_type;
// int[] styles={Font.PLAIN,Font.ITALIC,Font.BOLD,Font.ITALIC+Font.BOLD};
int[] styles={Font.PLAIN};
String[] stylenames={"Plain","Italic","Bold","Bold & Italic"};
Demo_Fonts()
{
setPreferredSize(new Dimension(500,3000));
}
public void paint(Graphics g)
{
for (int f=0;f<font_type.length;f++)
{
for (int s=0;s<styles.length;s++)
{
Font font=new Font(font_type[f],styles[s],18);
g.setFont(font);
String name=font_type[f]+" "+stylenames[s];
// g.drawString(name,20,(f*4+s+1)*20);
g.drawString(name,20,(f+s+1)*20);
}
}
}
public static void main(String[] a)
{
font_type=GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
for (int i=0;i<font_type.length;i++) System.out.println(font_type[i]);
JFrame f=new JFrame();
f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });
JScrollPane areaScrollPane=new JScrollPane(new Demo_Fonts());
areaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
areaScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
// areaScrollPane.setMinimumSize(new java.awt.Dimension(600,500));
areaScrollPane.setPreferredSize(new Dimension(500,1400));
f.setContentPane(areaScrollPane);
f.setSize(600,1400);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
But when I scroll down, the content is all messed up, why, and how to fix ?

Probably Your first line of paint should probably be super.paint(g). The parent paint() method will clear the panel.
When you scroll down, you paint on the component again. If you do not clear what you've already drawn, you'll just keep painting ontop of other stuff, leading to a mess.
Edit: I added this line and it works on my computer now.
Edit: As mKorbel suggests, you should really be overriding paintComponent instead of paint. paint is more for AWT, but it "works" for your program. If you work with Java Swing, you generally override paintComponent. So really, you should delete you paint method and replace it with
#Override
public void paintComponent(Graphics g)
{
super.paintComponent( g );
for (int f=0;f<font_type.length;f++)
{
for (int s=0;s<styles.length;s++)
{
Font font=new Font(font_type[f],styles[s],18);
g.setFont(font);
String name=font_type[f]+" "+stylenames[s];
// g.drawString(name,20,(f*4+s+1)*20);
g.drawString(name,20,(f+s+1)*20);
}
}
}

Related

Graphics Program Works on Windows but not on Mac

I wrote this program in java using swing. When I run this on my Mac each time repaint() is called fifty new blue points are made and the old blue points are erased. I have been doing a lot of research to try and fix this issue and I have had not luck. Then today in my computer science class I find out that the program works on the windows computers that are in the classroom. My question is why is this the case and how can I fix this so that the program works on my Mac? Also on a side note I am relatively new to using swing in java so I was wondering if I am organizing everything correctly and if I can do anything different?
This is the class where I draw everything within the JPanel.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Canvas;
import java.lang.Math;
import java.awt.event.*;
import javax.swing.*;
public class BarnsleyFern extends JPanel
{
private double newX,x=0;
private double newY,y=0;
public BarnsleyFern()
{
ActionListener action = new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
repaint();
}
};
Timer timer = new Timer(100,action);
//timer.start();
MouseListener mouse = new MouseListener()
{
public void mouseClicked(MouseEvent event)
{
//repaint();
}
public void mousePressed(MouseEvent event)
{
}
public void mouseReleased(MouseEvent event)
{
}
public void mouseEntered(MouseEvent event)
{
}
public void mouseExited(MouseEvent event)
{
}
};
MouseMotionListener mouseMotion = new MouseMotionListener()
{
public void mouseDragged(MouseEvent event)
{
repaint();
}
public void mouseMoved(MouseEvent event)
{
repaint();
}
};
addMouseListener(mouse);
addMouseMotionListener(mouseMotion);
}
public void paintComponent(Graphics window)
{
Graphics2D g2d = (Graphics2D)window;
g2d.translate(360,800);
fern(window);
}
public void fern(Graphics window)
{
Color newColor = new Color((int)(Math.random()*256),(int)(Math.random()*256),(int)(Math.random()*256));
for(int i=0;i<50;i++)
{
window.setColor(Color.BLUE);
int rand = (int)(Math.random()*100);
if(rand<1)
{
newX=0;
newY=0.16*y;
}
else if(rand<86)
{
newX=0.85*x + 0.04*y;
newY=0.85*y - 0.04*x + 1.6;
}
else if(rand<93)
{
newX=0.20*x - 0.26*y;
newY=0.23*x + 0.22*y + 1.6;
}
else
{
newX=0.28*y - 0.15*x;
newY=0.26*x + 0.24*y + 0.44;
}
window.fillOval((int)(newX*165.364),-(int)(newY*80.014),2,2);
x=newX;
y=newY;
}
}
}
This is the class that sets up the JFrame and adds the JPanel.
import javax.swing.*;
import java.awt.*;
public class BarnsleyFernRunner
{
public BarnsleyFernRunner()
{
JFrame frame = new JFrame();
frame.setTitle("Barnsley Fern");
frame.setSize(800,800);
frame.setLocation(300,0);
frame.setResizable(false);
frame.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
BarnsleyFern panel= new BarnsleyFern();
panel.setSize(800,800);
panel.setOpaque(true);
panel.setBackground(Color.BLACK);
frame.add(panel);
frame.setVisible(true);
}
public static void main(String[] args)
{
BarnsleyFernRunner runner = new BarnsleyFernRunner();
}
}
The "major" issue is, you're breaking the paint chain requirements...
public void paintComponent(Graphics window)
{
Graphics2D g2d = (Graphics2D)window;
g2d.translate(360,800);
fern(window);
}
The super implementation of paintComponent does something, something important, unless you're prepared to take over that responsibility, you should make sure you are calling super.paintComponent first
You issue isn't helped by...
frame.setSize(800,800);
frame.setLocation(300,0);
frame.setResizable(false);
frame.setLayout(null);
panel.setSize(800,800);
panel.setOpaque(true);
You should keep the default BorderLayout, it will make your life a lot simpler.
Simply by updating the BarnsleyFern to override the getPreferredSize you gain a much more flexible solution. This means you pack the window and the available content size will be the preferred size of the contents, as apposed to the size of the window MINUS the frame decorations.
public class BarnsleyFern extends JPanel {
//...
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
Based upon...
ActionListener action = new ActionListener() {
public void actionPerformed(ActionEvent event) {
repaint();
}
};
Timer timer = new Timer(100, action);
//timer.start();
I suspect you're hoping to get a compounding paint, where the x/y properties are updated on each paint cycle.
Well, that's not going to work, for a number of reasons. You've found one. Graphics is a shared resource, every component painted in a given paint cycle will use the same Graphics instance, this means you could end up with dirty paints (and as a side effect, the result you seem to be looking for), but as you've discovered, it doesn't always work.
Painting can also occur for any number of reasons, many without you control or knowledge.
Painting should paint the current state, it shouldn't modify it. This is what your Timer should be doing.
You need to devise a model which will allow a incremental change each time the Timer ticks, the component will then use the model to simply paint the current state
I would recommend reading:
Performing Custom Painting
Painting in AWT and Swing
Laying Out Components Within a Container
for more details

JPanel with JSlider not displaing the Graphics

All i have is a JPanel with a white background and the JSlider on the bottom, not displaying the square, i think i have made some mistake with the JPanel class but i can't figure it out. Just before i made another project with g.fillOval and it worked properly, i checked it out and every line of code seems the same, i am really confused.
public class Main00 {
public static void main(String[] args) {
Gui asd=new Gui();
asd.setVisible(true);
asd.setSize(500,400);
}
}
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
public class Gui extends JFrame {
private JSlider slider;
private DrawSquare square;
public Gui() {
super("square modificator");
setDefaultCloseOperation(EXIT_ON_CLOSE);
square = new DrawSquare();
square.setBackground(Color.WHITE);
slider = new JSlider(SwingConstants.HORIZONTAL, 0, 300,
square.getSide());
slider.setMajorTickSpacing(20);
slider.setPaintTicks(true);
add(square);
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
square.setSide(slider.getValue());
}
});
}
}
import java.awt.*;
import javax.swing.*;
public class DrawSquare extends JPanel {
private int side = 10;
public void paintComponents(Graphics g) {
super.paintComponents(g);
g.setColor(Color.RED);
g.fillRect(20, 20, side, side);
}
public void setSide(int side) {
this.side=(side>=0)?side:0;
repaint();
}
public Dimension getPrefferedSize(){
return new Dimension(200,200);
}
public Dimension getMinimumSize(){
return getPrefferedSize();
}
public int getSide(){
return side;
}
}
You're overriding paintComponents rather than the correct paintComponent. These two methods have drastically different effects, and the effect of the second is the one you want.
From the API:
paintComponents API entry: Paints each of the components in this container.
paintComponent API entry: Calls the UI delegate's paint method, if the UI delegate is non-null. We pass the delegate a copy of the Graphics object to protect the rest of the paint code from irrevocable changes
Again, you are interested in painting the component itself via its delegate and not in painting the components held by this component.

Can't print any string using drawString() in JFrame

I'm trying to find what is wrong with this short code. I can't print the String TEXT in my JFrame using drawString() method. Please Help . Only a plain white screen will appear if you run the program .
Code:
import javax.swing.*;
import java.awt.*;
public class sample extends JFrame
{
private JPanel panel;
public sample()
{
setSize(500,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
panel =new JPanel();
Container mainP= getContentPane();
mainP.add(panel);
panel.setBounds(0,0,500,500);
panel.setBackground(Color.WHITE);
}
public void paintComponent(Graphics g)
{
Graphics2D eg = (Graphics2D)g;
eg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
eg.setColor(Color.BLACK);
eg.drawString("TEXT", 40, 120);
}
public static void main(String args[])
{
new sample();
}
}
JFrame has no paintComponent method. So you aren't override anything, and not painting will be done.
On that note JPanel does have a paintComponent method, and you should be painting on a JComponent or JPanel, which do have the method. You don't want to paint on top-level containers like JFrame. (if you really need to know though, the correct method to override is paint for JFrame).
That being said, you should also call super.paintComponent inside the paintComponent method so you don't break the paint chain and leave paint artifacts.
Side Notes
As good practice, make use of the #Override annotation, so you know you are correctly overriding a method. You would've seen that paintComponent doesn't override one of JFrames methods.
setVisible(true) after add your components.
panel.setBounds(0,0,500,500); will do absolutely nothing, since the JFrame has a default BorderLayout
Follow Java naming convention and use capital letters for class names.
Run Swing apps from the Event Dispatch Thread. See more at Initial Threads
FINAL
import javax.swing.*;
import java.awt.*;
public class Sample extends JFrame {
private JPanel panel;
public Sample() {
setSize(500, 500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D eg = (Graphics2D) g;
eg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
eg.setColor(Color.BLACK);
eg.drawString("TEXT", 40, 120);
}
};
Container mainP = getContentPane();
mainP.add(panel);
panel.setBackground(Color.WHITE);
setVisible(true);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Sample();
}
});
}
}

JFrame not painting rectangle

Have a very simple issue which I haven't come across before. I used a similar layout before when doing a project.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class q1
{
public static void main (String Args [])
{
q1Window showMe = new q1Window();
}
}
class q1Window
{
q1Window()
{
JFrame window = new JFrame("Tutorial 1");
window.setSize(600,600);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint (Graphics back)
{
back.setColor(Color.black);
back.fillRect(30,30,100,200);
}
}
Now I can't seem to print anything however the JFrame shows.
You can't just add a paint() method to any class. Only Swing components have painting methods.
Read the section from the Swing tutorial on Custom Painting for more information and working examples.
Quick summary is that you need to override the paintComponent() method of a JPanel and then add the panel to the frame.
As camickr pointed out, you need a Swing component to do what you want, which in this case, is to override paint(), although you should be overriding paintComponent() instead.
Try this:
class q1 {
public static void main(String Args[]) {
q1Window showMe = new q1Window();
}
}
class q1Window extends JFrame {
q1Window() {
setTitle("Tutorial 1");
setSize(600, 600);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics back) {
back.setColor(Color.black);
back.fillRect(30, 30, 100, 200);
}
}

Can not draw oval on a JPanel

I have a JFrame created with GUI builder of Netbeans, which contains a JPanel only. I have created a method getPanel for getting a reference to this JPanel:
public class ShowDrawings extends JFrame {
public ShowDrawings() {
initComponents();
}
public JPanel getPanel(){
return panel;
}
private JPanel panel;
}
In my main function I am doing:
public class Main {
public static void main(String[] args){
ShowDrawings sd = new ShowDrawings();
sd.setSize(800, 600);
Graphics g = sd.getPanel().getGraphics();
g.setColor(Color.BLACK);
g.drawOval(400, 300, 50, 50);
sd.getPanel().paint(g);
sd.repaint();
sd.setVisible(true);
}
}
But it does not draw anything. Please help me.
I have looked some related questions but they are all suggesting extending JPanel and overriding its paint method. But I did not want to do that way.
Thanks.
I have looked some related questions but they are all suggesting
extending JPanel and overriding its paint method. But I did not want
to do that way
You should not override JPanel paint() method, rather paintComponent(..). This is best practice and should be done if you want code that will not produce anomalies. Also doing it in your current approach (as you have seen) makes creating persistent drawings a lot harder as they are wiped away on repaint()
Rather extend JPanel and override paintComponent(Graphics g) not forgetting to call super.paintComponent(g) as first call in overridden paintComponent(..) method. Also dont forget to override getPreferredSize() of JPanel so that we can return correct dimensions and pack() may be called on JFrame (+1 to #mKorbels comment):
Here is some example code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void initComponents() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel testPanel = new JPanel() {
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.GREEN);
//g2d.drawOval(10,10,100,100);//I like fill :P
g2d.fillOval(10,10,100,100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(150, 150);
}
};
frame.add(testPanel);
frame.pack();
frame.setVisible(true);
}
}
The first time you repaint() your ShowDrawings sd frame anything you've painted like this (sd.getPanel().getGraphics().drawOval(...)) would be erased by the original JPanel#paintComponent() method.
As Andrew Thompson has written:
Do not use Component.getGraphics(). Instead, subclass and override the paint() (AWT), or paintComponent() (Swing) method.
Component.getGraphics() simply can't work. Java uses a callback mechanism for drawing graphics. You are not supposed to "push" graphics information into a component using getGraphics(). Instead you are supposed to wait until Java calls your paint()/paintComponent() method. At that moment you are supposed to provide the Component with the drawings you would like to do.
If you're just checking/debugging something you could even do something like this:
class Test {
private JPanel panel = new JPanel() {
public void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
g.drawOval(400, 300, 50, 50);
}
};
}

Categories

Resources