Java graphics slow rendering of a draw methods. How to fix it? - java

Why the following code draws big space gap before circles equivalent to sum of consecutive executions of x=+10 statement?
class Panel extends JPanel {
private int x=10;
public void paintComponent( Graphics g ) {
super.paintComponent( g );
g.setColor( Color.MAGENTA );
for (int i=1; i<=8; i++) {
g.drawOval( x, 10, 50, 50 );
x+=10;
}
}
}
public class Circles156 {
public static void main(String[] args) {
JFrame frame = new JFrame( "Drawing lines, rectangles and ovals" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
Panel Panel = new Panel();
Panel.setBackground( Color.WHITE );
frame.add( Panel ); // add panel to frame
frame.setSize( 800, 300 ); // set frame size
frame.setVisible( true ); // display frame
}
}

Put x inside paintComponent() method.
Every time it is called, x is will increase the "initial value" by 80.

Related

Layered Java JPanels

I have overlayed JPanels, background has an image that prevents foreground from painting on applet's load.
setOpaque(false) works fine (repaints both panels twenty times thou[?]), but I need it opaque to have BG color, opaque background causes repainting itself 3 times, and that wipes out the top panel:
public class LayeredPanelsTest extends JApplet
{
private Image _image;
#Override
public void init()
{
_image = getImage( getDocumentBase(), "./images/flag.GIF" );
setSize( 450, 450 );
setLayout( new OverlayLayout( getContentPane() ) );
final BottomPanel background = new BottomPanel();
background.setBounds( 10, 10, 400, 400 );
final TopPanel foreGround = new TopPanel();
foreGround.setBounds( 10, 10, 400, 400 );
add( foreGround );
add( background );
}
public class BottomPanel extends JPanel
{
public BottomPanel()
{
setBackground(Color.CYAN);
setLayout( new FlowLayout() );
setOpaque( true );//with false foreground is painted just fine, but they get repainted like 20 times.
}
#Override
public void paintComponent( final Graphics g )
{
super.paintComponent( g );
g.drawImage( _image, 10, 10, this );
System.out.println( "Bottom" );
}
}
public class TopPanel extends JPanel
{
int _mouseX = 10;
public TopPanel()
{
setLayout( new FlowLayout() );
setOpaque( false );
addMouseListener( new MouseAdapter()
{
#Override
public void mousePressed( final MouseEvent evt ) {
_mouseX = evt.getX();
repaint();
}
});
}
#Override
public void paintComponent( final Graphics g )
{
super.paintComponent( g );
g.drawLine( _mouseX, 0, _mouseX, 80);
System.out.println( "Top" );
}
}
}

How to draw a Guide Marker for the Viewport of JScrollPane

I have JFrame, which contains a Jscrollpane which in turn contains a Jpanel with image being displayed in it. All the mouse events and drawing is respect to the Jpanel cordinates. Now, I want to put a guide lines marker on top of the ViewPort, The marker should remain constant irrespective of the image being zoomed or panned. What is the best way to do it? Thanks in advance.
You can do custom painting on the viewport of the scroll pane:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
public class ViewportBackground
{
private static void createAndShowUI()
{
JViewport viewport = new JViewport()
{
#Override
protected void paintChildren(Graphics g)
{
super.paintChildren(g);
int w = this.getWidth();
int h = this.getHeight();
g.drawLine(0, 0, w, h);
}
};
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewport(viewport);
scrollPane.setViewportView( new JLabel( new ImageIcon(...) ) );
JFrame frame = new JFrame("Viewport Background");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( scrollPane );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}

frame.repaint() not working

This is a source I got directly from "Head First Java" but whatever I do I can't seem to make it work, and I don't know what I may be missing
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SimpleGui3C implements ActionListener {
JFrame frame;
public static void main(String[] args) {
SimpleGui3C gui = new SimpleGui3C();
gui.go();
}
public void go() {
MyDrawPanel drawPanel = new MyDrawPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Change colors");
button.addActionListener(this);
frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
frame.repaint();
}
}
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, 300, 300);
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
Color randomColor = new Color(red, green, blue);
g.setColor(randomColor);
g.fillOval(70, 70, 100, 100);
}
}
I tried to find another way to do it which doesn't involve repaint but rather createing a new instance of MyDrawPanel whenever the event occurs, but it still doesn't work since I didn't found a way to clear the panel properly, the only hack I've found so far is to do this, but it's not what I want to acheive ...
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SimpleGui3C implements ActionListener {
JFrame frame;
public static void main(String[] args) {
SimpleGui3C gui = new SimpleGui3C();
gui.go();
}
public void go() {
MyDrawPanel drawPanel = new MyDrawPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Change colors");
button.addActionListener(this);
frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
go();
}
}
class MyDrawPanel extends JPanel {
int red;
int green;
int blue;
public MyDrawPanel() {
this.red = (int) (Math.random() * 255);
this.green = (int) (Math.random() * 255);
this.blue = (int) (Math.random() * 255);
}
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, 300, 300);
Color randomColor = new Color(this.red, this.green, this.blue);
g.setColor(randomColor);
g.fillOval(70, 70, 100, 100);
}
}
While dealing with Swing, one should keep some thingies in mind. As I looked at the code used by you, I felt like pointing it out to you, to be on the right track.
Swing based applications are started from their own respective
thread, called the EventDispatcherThread ( EDT ) and not directly
from main. More information, on the topic can be found on
Concurrency in Swing
Try not to perform any calculations inside the paintComponent ( ...
) method, instead perform these calculations somewhere else, and
simply call repaint ()
The access specifier of paintComponent ( ... ) is protected and
not public, hence while overriding methods of super class, try not
to change the methods access as much as possible, until not
necessary.
When you are drawing on a JPanel, simply call the repaint () on
the instance of the JPanel, instead of the top level container's
When one is extending any JComponenet/JPanel, always try to
override, the said JComponent/JPanel's getPreferredSize (), as
many a layouts will return 0, if none is specified, hence no
painting will be done.
Do remember to call super.paintComponent ( g ), as the first line
inside paintComponent ( ... ). Added a comment for more clarity.
Instead of setting size on JFrame, try to call pack (), as
stated in Java Docs for the benefits attached. The pack method
sizes the frame so that all its contents are at or above their
preferred sizes. An alternative to pack is to establish a frame size
explicitly by calling setSize or setBounds (which also sets the
frame location). In general, using pack is preferable to calling
setSize, since pack leaves the frame layout manager in charge of the
frame size, and layout managers are good at adjusting to platform
dependencies and other factors that affect component size.
Here is the modified code ( just added a method inside DrawPanel, called setValues (), where calculations are done and repaint () is called ), based on above points:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SimpleGui implements ActionListener {
private MyDrawPanel drawPanel;
public static void main(String[] args) {
Runnable r = new Runnable () {
#Override
public void run () {
new SimpleGui ().go ();
}
};
EventQueue.invokeLater ( r );
}
public void go() {
drawPanel = new MyDrawPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
JButton button = new JButton( "Change colors" );
button.addActionListener( this );
frame.add( drawPanel, BorderLayout.CENTER );
frame.add( button, BorderLayout.PAGE_END );
frame.pack ();
frame.setLocationByPlatform ( true );
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
drawPanel.setValues ();
}
}
class MyDrawPanel extends JPanel {
private int width = 300;
private int height = 300;
private int red;
private int green;
private int blue;
private Color randomColor;
/*
* Make this one customary habbit,
* of overriding this method, when
* you extends a JPanel/JComponent,
* to define it's Preferred Size.
* Now in this case we want it to be
* as big as the Image itself.
*/
#Override
public Dimension getPreferredSize () {
return new Dimension ( width, height );
}
public void setValues () {
red = ( int ) ( Math.random() * 255 );
green = ( int) ( Math.random() * 255 );
blue = ( int ) ( Math.random() * 255 );
randomColor = new Color( red, green, blue );
repaint ();
}
/*
* This is where the actual Painting
* Code for the JPanel/JComponent goes.
* Here the first line super.paintComponent(...),
* means we want the JPanel to be drawn the usual
* Java way first (this usually depends on the opaque
* property of the said JComponent, if it's true, then
* it becomes the responsibility on the part of the
* programmer to fill the content area with a fully
* opaque color. If it is false, then the programmer
* is free to leave it untouched. So in order to
* overcome the hassle assoicated with this contract,
* super.paintComponent(g) is used, since it adheres
* to the rules, and performs the same task, depending
* upon whether the opaque property is true or false),
* then later on we will add our image to it, by
* writing the other line, g.drawImage(...).
*/
#Override
protected void paintComponent(Graphics g) {
super.paintComponent ( g );
g.setColor(randomColor);
g.fillOval(70, 70, 100, 100);
}
}
This will do what you want....
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SimpleGui3C implements ActionListener {
static JFrame frame = null; // changed here...
public static void main(String[] args) {
frame = new JFrame(); // changed here....
SimpleGui3C gui = new SimpleGui3C();
gui.go();
}
public void go() {
MyDrawPanel drawPanel = new MyDrawPanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Change colors");
button.addActionListener(this);
frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
frame.repaint();
}
}
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, 300, 300);
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
Color randomColor = new Color(red, green, blue);
g.setColor(randomColor);
g.fillOval(70, 70, 100, 100);
}
}
In your go() method... Everytime you are creating a new object by JFrame frame = new JFrame(); and hence on your every click a new frame appears on the screen...
By creating the object in main() method we are only calling the repaint() method everytime on the same jframe object and not creating a new object....
Hoping it helped...

Translucent internal frames - is that possible in java?

Is there any way I can make translucent JInternalFrame uing swing?
All I found is option for JFrame(not internal one) which is not what I need.
You should be able to use a JLayer. You could start with the layout painting a fully opaque layer the same color as the background of the desktop pane. Then you change the alpha value to approach cell until you have full transparency.
See the section from the Swing tutorial on How to Decorate Components With the JLayer Class for more information and an example of painting with transparency.
If you only care about the background you can use the Alpha Container when using components with transparency:
JPanel content = new JPanel( new BorderLayout() );
content.setBackground( new Color(0, 0, 0, 0) );
internalFrame.setContentPane(new AlphaContainer(content));
internalFrame.setOpaque(false);
You can then change the alpha value of the content panel to your desired transparency.
Edit:
Here is may attempt at animating the transparency of an internal frame and its components:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class TransparentInternalFrame extends JInternalFrame implements ActionListener
{
static int openFrameCount = 0;
static final int xOffset = 30, yOffset = 30;
private float alpha = 0.0f;
private Timer timer = new Timer(500, this);
public TransparentInternalFrame()
{
super("Document #" + (++openFrameCount), true, true, true, true);
setSize(300,300);
setLocation(xOffset * openFrameCount, yOffset * openFrameCount);
setVisible( true );
}
#Override
public void paint(Graphics g)
{
g.setColor( getDesktopPane().getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
Graphics2D g2 = (Graphics2D)g.create();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
super.paint(g2);
}
public void showFrame()
{
timer.start();
}
public void hideFrame()
{
alpha = 0.0f;
repaint();
}
#Override
public void actionPerformed(ActionEvent e)
{
alpha += .05f;
alpha = Math.min(1.0f, alpha);
System.out.println(alpha);
if (alpha >= 1.0f)
timer.stop();
repaint();
}
private static void createAndShowGUI()
{
JDesktopPane desktop = new JDesktopPane();
desktop.setBackground( Color.YELLOW );
TransparentInternalFrame tif = new TransparentInternalFrame();
desktop.add( tif );
tif.add(new JButton("Hello"), BorderLayout.PAGE_START);
JButton show = new JButton( "Show Internal Frame" );
show.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
tif.showFrame();
}
});
JButton hide = new JButton( "Hide Internal Frame" );
hide.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
tif.hideFrame();
}
});
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(show, BorderLayout.PAGE_START);
frame.add(desktop);
frame.add(hide, BorderLayout.PAGE_END);
frame.setLocationByPlatform( true );
frame.setSize(500, 500);
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}

Adding elements to JPanel

Why does "drawing" not appear here? I am adding it to a different JPanel then adding everything to another JPanel and returning that. However, all i see is the TrackBall
public class Draw extends JFrame
{
private JSplitPane itemPane;
private Point position = null;
public Draw()
{
// Set the layout to a grid
setLayout ( new BorderLayout (5,5));
// Set the properties of the window
setTitle ("Emulator");
setSize ( 900, 700);
setDefaultCloseOperation (EXIT_ON_CLOSE);
setBackground ( new Color (15, 255, 10));
// Add the components
addComponents ();
}
public static void startWindowsGui()
{
// We are in the static main, set the form to invoke later
SwingUtilities.invokeLater ( new Runnable()
{
public void run()
{
// Create a new instance of server and set it to visible
Draw gui = new Draw();
gui.setVisible (true);
}
} );
}
private void addComponents()
{
// Create the main and an itemPane
JSplitPane mainPane = new JSplitPane ( JSplitPane.HORIZONTAL_SPLIT );
setItemPane(new JSplitPane ( JSplitPane.VERTICAL_SPLIT ));
mainPane.add ( createPane ( ), JSplitPane.LEFT );
mainPane.add ( getItemPane(), JSplitPane.RIGHT );
mainPane.setOneTouchExpandable ( true );
getItemPane().setOpaque(true);
getItemPane().setBackground(new Color(0xffffffc0));
JPanel p = new JPanel();
this.getItemPane().add(p);
add ( mainPane, BorderLayout.CENTER );
}
public static void main(final String[] args)
{
Runnable gui = new Runnable()
{
#Override
public void run()
{
new Draw().setVisible(true);
}
};
SwingUtilities.invokeLater(gui);
}
private class Drawing extends JPanel {
private static final long serialVersionUID = 1L;
private final Point position;
public Drawing(Point position) {
this.position = position;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.RED);
g2.fillOval(160 + position.x, 160 - position.y, 15, 15);
}
}
private JPanel createPane()
{
// Create the feedPanel
JPanel panel = new JPanel ( );
JPanel panel2 = new JPanel ( );
JPanel panel3 = new JPanel ( );
this.position = new Point();
TrackBall myJoystick = new TrackBall(150, position, 100);
panel.add(myJoystick, BorderLayout.PAGE_END);
Drawing drawing = new Drawing(position);
panel2.add(drawing, BorderLayout.PAGE_START);
panel3.add(panel2);
panel3.add(panel);
return panel3;
}
public JSplitPane getItemPane() {return itemPane;}
public void setItemPane(JSplitPane itemPane) {this.itemPane = itemPane;}
}
3 issues
panel2 requires BorderLayout rather than the default FlowLayout for the BorderLayout.PAGE_START constraint to be used
The class Drawing is required to override getPreferredSize
The Dimension specified by getPreferredSize should be large enough to accommodate the position specified in the constructor of Drawing
Read: Changing preferred size of a Swing component

Categories

Resources