java JTextField paintComponent Method called repeatedly. Is that normal? - java

having subclassed JTextField, I noticed the paintComponent Method is called repeatedly (approximately every half-a-second) when the Field has Focus, even with no user interaction.
I read the Oracle article "Painting in AWT and Swing", but didn't find any enlightenment there.
Is this normal behaviour, or have a missed something?
Here's my example Proggy:
(positioning the Cursor in the 2nd - not subclassed - JTextField which has no logging, causes the subclassed one with logging to lose Focus which stops being repeatedly repainted)
import java.awt.*;
import javax.swing.*;
public class SwingPaintDemo2 extends JFrame {
public SwingPaintDemo2(final String title) {
super(title);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Box box = new Box(BoxLayout.Y_AXIS);
box.add(new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(250, 200);
}
#Override
public void paintComponent(final Graphics g) {
super .paintComponent( g);
System.out.println("MyPanel.paintComponent......: " + g);
g.drawString("This is my custom Panel!", 10, 20);
}
});
box.add(new JTextField("JayTekst") {
#Override
public void paintComponent(final Graphics g) {
super .paintComponent( g);
System.out.println("JayTextField.paintComponent.: " + g);
}
});
box.add(new JTextField("JText"));
this.add(box);
this.pack();
this.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> new SwingPaintDemo2("Swing Paint Demo"));
}
}

Of course it is normal. When the textfield has focus, you can see the cursor blinking which means you see the textfield with new a visual representation, which means paintComponent().

Related

Trying to draw lines in java over an image i already drew but i can't get it on top of the image?

I have to draw an archery target with two black lines in the innermost circle that forms a cross, but every time i adjust the lines so that the lines are closer to the centre it goes behind the image instead of appearing on top. How can I stop this? Does it need to have a separate set of instructions entirely?
This is my code:
package sumshapes;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.*;
import javax.swing.*;
public class SumShapes extends JFrame
implements ActionListener {
private JPanel panel;
public void paint(Graphics g)
{
g.setColor(Color.BLACK);
g.drawLine(250, 200, 250, 200);
g.drawOval(140,90,200,200);
g.setColor(Color.BLACK);
g.fillOval(140,90,200,200);
g.drawOval(162,109,155,155);
g.setColor(Color.BLUE);
g.fillOval(162,109,155,155);
g.drawOval(183,129,112,112);
g.setColor(Color.RED);
g.fillOval(183, 129, 112, 112);
g.drawOval(210,153,60,60);
g.setColor(Color.YELLOW);
g.fillOval(210, 153, 60, 60);
g.setColor(Color.BLACK);
}
public static void main(String[] args) {
SumShapes frame = new SumShapes();
frame.setSize(500,400);
frame.setBackground(Color.yellow);
frame.createGUI();
frame.setVisible(true);
}
private void createGUI(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container window = getContentPane();
window.setLayout (new FlowLayout());
}
public void actionPerformed(ActionEvent event) {
Graphics paper = panel.getGraphics();
paper.drawLine(20,80,120,80);
}
}
All your drawing should go into the paintComponent method of a lightweight component, such as a JPanel.
There should never be a need to call getGraphics. If you wish to change the drawing upon a particular action you should a) program the logic into paintComponent b) alter the logic in the Action c) call repaint on the Component
For example:
private JPanel panel = new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);//call parent method first thing
//paint here
}
#Override
public Dimension getPreferredSize(){//provided so you can size this component as necessary
return new Dimension(500,400);
}
};
....
frame.add(panel);
frame.pack();
As an aside, I'd recommend placing all calls to to Swing components on the EDT - this means wrapping your Swing calls in the main method with SwingUtilities. eg
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable(){
#Override
public void run() {
SumShapes frame = new SumShapes();
....
}
});
}

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.

Why is my Swing app not displaying properly?

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);
}
}
}

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();
}
});
}
}

draw rectangle in Jpanel

I am trying to get my hands on GUI programming in java and wanted to draw a rectangle in Jpanel. Code does not give any error but I cannot get rectangle in the GUI. Can somebody please tell me what I am missing in the following code. I am sure it is pretty simple so please be gentle.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class HelloWorldGUI2 {
private static class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
private static class RectDraw extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(230,80,10,10);
g.setColor(Color.RED);
g.fillRect(230,80,10,10);
}
}
public static void main(String[] args) {
JPanel content = new JPanel();
RectDraw newrect= new RectDraw();
JButton okButton= new JButton("OK");
JButton clearButton= new JButton("Clear");
ButtonHandler listener= new ButtonHandler();
okButton.addActionListener(listener);
clearButton.addActionListener(listener);
content.add(okButton);
content.add(clearButton);
content.add(newrect);
JFrame window = new JFrame("GUI Test");
window.setContentPane(content);
window.setSize(250,100);
window.setLocation(100,100);
window.setVisible(true);
}
}
Your newrect RectDraw's size is likely going to be quite small, probably [0, 0], since it has been added to a FlowLayout using JPanel and doesn't have a preferredSize set. Consider overriding its getPreferredSize() method and returning a suitable Dimension so that its drawing can be seen.
private static class RectDraw extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(230,80,10,10);
g.setColor(Color.RED);
g.fillRect(230,80,10,10);
}
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H); // appropriate constants
}
}
Also,
The paintComponent method should be protected, not public
Don't forget to use #Override before your method overrides.
Aim for much less code in the main method and more code in the "instance" world, not the static world.
Take care with your code formatting. Poor code formatting, especially misleading indentations, leads to silly errors.

Categories

Resources