Found this sample code which should produce a drawn line after clicking, but does not show anything or works. Assume all import statements are correct, code gives no errors and I have no idea why it would not work. The line color is red while the background is white so it should show clearly if it works. The mouse listener seems to be correct as well. Any reason why this code will not work?
public class PathPanel extends JPanel {
/**
* The panel width.
*/
public static final int WIDTH = 400;
/**
* The panel height.
*/
public static final int HEIGHT = 400;
/**
* The background color of the panel.
*/
public static final Color BACKGROUND_COLOR = Color.WHITE;
/**
* The color to paint with.
*/
public static final Color FOREGROUND_COLOR = Color.RED;
/**
* The line width.
*/
public static final int LINE_WIDTH = 8;
// Instance Fields
/**
*
*/
private static final long serialVersionUID = -3644129903653409515L;
/**
* The path being created.
*/
private final Path2D myPath;
// OR you could use Path2D.Double instead of GeneralPath
// Constructor
/**
* Constructs a new general path panel.
*/
public PathPanel() {
super();
myPath = new GeneralPath();
myPath.setWindingRule(GeneralPath.WIND_EVEN_ODD);
//myPath = new Path2D.Double();
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(BACKGROUND_COLOR);
addMouseListener(new MyMouseListener());
}
/**
* Paints the current path.
*
* #param theGraphics The graphics context to use for painting.
*/
#Override
public void paintComponent(final Graphics theGraphics) {
super.paintComponent(theGraphics);
final Graphics2D g2d = (Graphics2D) theGraphics;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(FOREGROUND_COLOR);
g2d.setStroke(new BasicStroke(LINE_WIDTH));
g2d.draw(myPath);
}
// Main Method
/**
* Creates and displays a GeneralPathPanel.
*
* #param theArgs Command line arguments (ignored).
*/
public static void main(final String... theArgs) {
final PathPanel panel = new PathPanel();
final JFrame frame = new JFrame("GeneralPathPanel Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
// Inner Class
/**
* Listens for mouse clicks, to draw on our panel.
*/
private class MyMouseListener extends MouseAdapter {
/**
* Handles a click event.
*
* #param theEvent The event.
*/
#Override
public void mouseClicked(final MouseEvent theEvent) {
if (myPath.getCurrentPoint() == null) {
myPath.moveTo(theEvent.getX(), theEvent.getY());
} else if (theEvent.getClickCount() == 2) {
myPath.closePath();
} else {
myPath.lineTo(theEvent.getX(), theEvent.getY());
}
repaint();
}
}
}
The Sample Code you posted works fine for me. Have you tried to add a System.out.println() in the mouseClicked(final MouseEvent theEvent) Method to check if it is actually called? If it is not called, you could try to change it to mouseReleased.
The imports I used:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
Related
So I'm desinging an application for offline quiz systems. Currently I'm working on the screen that is visible for the participants (only question, maybe possible answers and a media element).
This screen contains a slide (derived from JPanel) the screen itself is a JFrame. I have to use the JPanel in another JFrame. In the JPanel of the slide is another JPanel for displaying media. I succeeded to display an image in the JPanel. But the application also has to display video and audio. I use VLCj to realize this in my application. Here is the code of the JFrame of the SlideView.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
/**
* Created by bram on 30/03/17.
*/
public class SlideView
{
private SlidePanel slidePanel;
private JFrame frame;
public SlideView(){
slidePanel = new SlidePanel();
frame = new JFrame("SlideView");
frame.setLayout(new BorderLayout());
Dimension dim = new Dimension();
dim.setSize(800,450);
frame.setMinimumSize(dim);
frame.add(slidePanel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
frame.addComponentListener(new ComponentListener() {
public void componentMoved(ComponentEvent e){}
public void componentHidden(ComponentEvent e){}
public void componentShown(ComponentEvent e){}
public void componentResized(ComponentEvent e)
{
frame.add(slidePanel,BorderLayout.CENTER);
}
});
}
/**
* Display the information of the slide
* #pre slide has to be initialized
* #pre the slideview is initialized
* #param slide the slide that has to be displayed
* #post the slide will be displayed
*/
public void setSlide(Slide slide)
{
slidePanel.initializeSlide(slide);
}
/**
* Set the slide panel
* #param panel
*/
public void setSlidePanel(SlidePanel panel)
{
frame.remove(slidePanel);
slidePanel = panel;
frame.add(slidePanel);
}
/**
* Get the slide panel
* #return the slide panel
*/
public SlidePanel getSlidePanel()
{
return slidePanel;
}
}
And here is the code of the panel that contains the information of the slide:
import javax.swing.*;
import java.awt.*;
import java.net.URL;
/**
* Created by bram on 30/03/17.
*/
public class SlidePanel extends JPanel {
private ImageIcon bgImage;
private JLabel title, body;
private Slide slide;
private MediaView media;
public SlidePanel()
{
bgImage = new ImageIcon("/home/bram/Documenten/School/3 BA/PSOPV/LOCAL/src/Slides/slide_background.jpg");
this.setSize(800,450);
createComponents();
}
/**
* Get the media view for controlling it
*/
public MediaView getMediaView()
{
return media;
}
/**
* Initialize the slide
*/
public void initializeSlide(Slide slide)
{
this.slide = slide;
title.setText(slide.getTitle());
body.setText(slide.getBodyText());
media.setFile(slide.getMediaFile());
resizeComponents();
}
#Override
/**
* Actions that will be executed when the window is resized
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw the background image.
g.drawImage(getResizedBackground().getImage(), 0, 0, this);
resizeComponents();
}
/**
* Resize the different components to the dimensions of the frame
*/
private void resizeComponents()
{
/*Calculate the growing factor of the screen (minimum size is 800*450)*/
float growFactor = (float) this.getWidth() / 800f;
/*Scale the title label*/
title.setFont(new Font("SansSerif", Font.BOLD, (int)(40*growFactor)));
title.setBounds((int)(20 * growFactor), (int)(20*growFactor),this.getWidth(), (int)(50 * growFactor));
/*Scale the body section*/
body.setFont(new Font("SansSerif", Font.PLAIN,(int)(25*growFactor)));
body.setBounds((int)(50*growFactor),(int)(0.25f*this.getHeight()),(int)((this.getWidth()-50*growFactor) * 0.5f), (int)(0.75f*this.getHeight()-20));
/*Scale the media section*/
media.setBounds((int)(this.getWidth()*0.5),(int)(this.getHeight()*0.30), (int)(this.getWidth() * 0.40),(int)(this.getHeight()*0.60-20));
}
/**
* Create the title label of the slide
*/
private void createTitle()
{
title = new JLabel("",SwingConstants.LEFT);
title.setForeground(Color.WHITE);
this.add(title);
}
/**
* Create the body of the slide
*/
private void createBody()
{
body = new JLabel("");
this.add(body);
}
/**
* Create the media section
*/
private void createMedia()
{
media = new MediaView();
media.setSize(100,100);
this.add(media);
}
/**
* Create the gui components for displaying a slide
*/
private void createComponents()
{
createTitle();
createBody();
createMedia();
}
/**
* Scale the background to the height and width of the panel
* #return the resized background
*/
private ImageIcon getResizedBackground()
{
Image img = bgImage.getImage();
img = img.getScaledInstance(this.getWidth(),this.getHeight(), Image.SCALE_DEFAULT);
return new ImageIcon(img);
}
}
And finally here is the JPanel that has to display the media:
import com.sun.jna.NativeLibrary;
import uk.co.caprica.vlcj.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import uk.co.caprica.vlcj.player.embedded.videosurface.CanvasVideoSurface;
import uk.co.caprica.vlcj.player.media.Media;
import uk.co.caprica.vlcj.runtime.RuntimeUtil;
import javax.swing.*;
import java.awt.*;
import java.net.URL;
/**
* Created by bram on 31/03/17.
*/
public class MediaView extends JPanel
{
private MediaFile file;
//Label for displaying a picture
private JLabel picture;
//Media player for video and audio
private EmbeddedMediaPlayerComponent mediaPlayer;
private int width,height;
private static final String NATIVE_LIBRARY_SEARCH_PATH = "lib";
/**
* Default constructor for the mediaview class
*/
public MediaView()
{
setOpaque(false);
setLayout(new GridBagLayout());
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), NATIVE_LIBRARY_SEARCH_PATH);
this.width = getWidth();
this.height = getHeight();
}
/**
* Add the appropriate components to the panel
*/
private void addComponents()
{
if(file.getFileType() == MediaFile.FileType.PICTURE)
{
picture = new JLabel();
this.add(picture);
}
if(file.getFileType() == MediaFile.FileType.VIDEO)
{
mediaPlayer = new EmbeddedMediaPlayerComponent();
setLayout(new BorderLayout());
add(mediaPlayer, BorderLayout.CENTER);
mediaPlayer.setSize(this.getWidth(),this.getHeight());
}
}
/**
* Set the media file to be displayed
* #pre the media file is initialized
* #param file the file that has to be displayed
*/
public void setFile(MediaFile file)
{
this.file = file;
addComponents();
generateView();
}
#Override
/**
* Actions that will be executed when the window is resized
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(this.height != getHeight() || this.width != getWidth())
{
generateView();
height = getHeight();
width = getWidth();
}
}
/**
* Generate the view of the file
*/
private void generateView()
{
if(file == null)
return;
if(file.getFileType() == MediaFile.FileType.PICTURE)
generateImage();
if(file.getFileType() == MediaFile.FileType.VIDEO)
generateVideo();
if(file.getFileType() == MediaFile.FileType.AUDIO)
generateAudio();
}
/**
* Generate the view of an audio file
*/
private void generateAudio()
{
}
/**
* Generate the view of a video
*/
public void generateVideo()
{
//Resize canvas
//Load native library of VLC
}
public void playMedia()
{
mediaPlayer.getMediaPlayer().playMedia(file.getPath());
}
/**
* Generate the view of an image
*/
private void generateImage()
{
/*Get the image by path*/
ImageIcon image = new ImageIcon(file.getPath());
/*Scale the image*/
Image img = image.getImage();
if(image.getIconHeight() > image.getIconWidth()) {
float growFactor = (float) this.getHeight() / (float) image.getIconHeight();
int width = (int) (image.getIconWidth() * growFactor);
img = img.getScaledInstance(width, this.getHeight(), Image.SCALE_DEFAULT);
} else {
float growFactor = (float) this.getWidth() / (float) image.getIconWidth();
int height = (int) (image.getIconHeight() * growFactor);
img = img.getScaledInstance(this.getWidth(),height,Image.SCALE_DEFAULT);
}
ImageIcon pic = new ImageIcon(img);
/*Set image as label icon*/
picture.setIcon(pic);
/*Set the bounds of the label*/
int xCoordinate = (this.getWidth() - pic.getIconWidth())/2;
int yCoordinate = (this.getHeight() - pic.getIconHeight())/2;
picture.setHorizontalAlignment(JLabel.CENTER);
picture.setVerticalAlignment(JLabel.CENTER);
picture.setBounds(xCoordinate,yCoordinate,picture.getWidth(),picture.getHeight());
}
}
But the video won't display (the video is a MP4 format). I tried several things (the above is the best result) does anyone can help me?
I have a JPanel with an overriden paintComponent. I want to make certain elements that I manually draw on this panel focusable so that people using assistive technologies could use my application using keyboard.
If you could give me a few pointers that would be awesome.
You can do the following:
Convert your elements into JComponents.
Set the LayoutManager of your panel to null. You will then add all your components/elements into this panel and you can move them freelly around with the method Component.setBounds(...).
Add a MouseListener in your panel which will transfer the focus to the selected component, for each mouse press.
You can determine which component was pressed by calling the method Component.getComponentAt(Point) inside the MouseListener of your panel.
Simple example:
Make a component with the standard behaviour of showing the user if it has focus or not. In my example-code below this class is FocusableComponent extends JComponent, which draws a blue rectangle around the component if it has focus (this is done inside the method FocusableComponent.paintComponent(Graphics)).
Then, for each distinct "element" you draw, subclass FocusableComponent and override its paintComponent(Graphics) method to paint the element. Make sure you call "super.paintComponent(Graphics)" inside there for the blue rectangle to be drawn (if it has focus).
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FocusablePaintComps {
private static abstract class FocusableComponent extends JComponent {
#Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
if (hasFocus()) {
final Color prevColor = g.getColor();
g.setColor(Color.BLUE);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g.setColor(prevColor);
}
}
}
private static class FocusableComponent1 extends FocusableComponent {
#Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
g.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
}
}
private static class FocusableComponent2 extends FocusableComponent {
#Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
final int w = getWidth(), h = getHeight();
g.fillRect(20, 20, w - 40, h - 40);
g.fillArc(10, 10, w - 1, h - 1, 60, 150);
}
}
private static class YourPanel extends JPanel {
private Component previousFocusedComponent = null;
private YourPanel() {
super(null); //Null LayoutManager. This is important to be able to
//move added components around freelly (with the method setBounds(...)).
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(final MouseEvent evt) {
final Component src = getComponentAt(evt.getPoint());
if (src instanceof FocusableComponent) {
final FocusableComponent fc = (FocusableComponent) src;
fc.requestFocusInWindow(); //Transfer focus to the pressed component.
if (previousFocusedComponent != null)
previousFocusedComponent.repaint(); //Repaint the last (without focus now).
setComponentZOrder(fc, 0); //Update: To make fc paint over all others as
//the user http://stackoverflow.com/users/131872/camickr commented.
fc.repaint(); //Repaint the new (with focus now).
previousFocusedComponent = fc;
}
else { //If clicked on empty space, or a non-FocusableComponent:
requestFocusInWindow(); //Tranfer focus to somewhere else (e.g. the panel itself).
if (previousFocusedComponent != null) {
previousFocusedComponent.repaint(); //Repaint the last (without focus now).
previousFocusedComponent = null;
}
}
}
});
setPreferredSize(new Dimension(250, 250));
add(new FocusableComponent1(), Color.RED, new Rectangle(10, 10, 200, 20));
add(new FocusableComponent1(), Color.GREEN, new Rectangle(40, 150, 50, 70));
add(new FocusableComponent2(), Color.GRAY, new Rectangle(60, 125, 90, 100));
add(new FocusableComponent2(), Color.MAGENTA, new Rectangle(150, 60, 80, 150));
}
private void add(final FocusableComponent fc, final Color fgColor, final Rectangle bounds) {
fc.setForeground(fgColor);
add(fc);
fc.setBounds(bounds);
}
}
public static void main(final String[] args) {
final JFrame frame = new JFrame("Focused Paint Comps");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new YourPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Screenshot:
Some notes:
The sequence in which the focus is transfered in relation to the sequence in which the rapaint()s are called inside mousePressed(...) determines which component will have the blue rectanlge around it, and which not.
Method Component.getElementAt(Point) does not "see through" transparent/non-opaque pixels.
Update:
Note: This update is an optional expansion (but maybe a more java-contract-consistent - let me put it) of the above solution. You may read only one of two implementations (either the following "update" one with RandomLayout, either the above "pre-update" one with null LayoutManager).
Follows an update of the above code, which uses a custom LayoutManager to lay-out the components in the container, as suggested by user "Andrew Thompson" in comments.
The only difference from the above code is that instead of setting to null the LayoutManager upon construction of the YourPanel, a new instance of the custom LayoutManager is used and instead of setting the bounds for each component, you only need to set its size.
I have named the custom LayoutManager to RandomLayout and it places all the components of the container in random positions, taking into account the size of the components and the Insets of the container (this is demonstrated by the added Border in the YourPanel).
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class FocusablePaintComps {
private static abstract class FocusableComponent extends JComponent {
#Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
if (hasFocus()) {
final Color prevColor = g.getColor();
g.setColor(Color.BLUE);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g.setColor(prevColor);
}
}
}
private static class FocusableComponent1 extends FocusableComponent {
#Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
g.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
}
}
private static class FocusableComponent2 extends FocusableComponent {
#Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
final int w = getWidth(), h = getHeight();
g.fillRect(20, 20, w - 40, h - 40);
g.fillArc(10, 10, w - 1, h - 1, 60, 150);
}
}
private static class YourPanel extends JPanel {
private Component previousFocusedComponent = null;
private YourPanel() {
super(new RandomLayout()); //RandomLayout: custom LayoutManager which lays
//out the components in random positions (takes Insets into account).
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(final MouseEvent evt) {
final Component src = getComponentAt(evt.getPoint());
if (src instanceof FocusableComponent) {
final FocusableComponent fc = (FocusableComponent) src;
fc.requestFocusInWindow(); //Transfer focus to the pressed component.
if (previousFocusedComponent != null)
previousFocusedComponent.repaint(); //Repaint the last (without focus now).
setComponentZOrder(fc, 0); //Update: To make fc paint over all others as
//the user http://stackoverflow.com/users/131872/camickr commented.
fc.repaint(); //Repaint the new (with focus now).
previousFocusedComponent = fc;
}
else { //If clicked on empty space, or a non-FocusableComponent:
requestFocusInWindow(); //Tranfer focus to somewhere else (e.g. the panel itself).
if (previousFocusedComponent != null) {
previousFocusedComponent.repaint(); //Repaint the last (without focus now).
previousFocusedComponent = null;
}
}
}
});
setBorder(new LineBorder(Color.LIGHT_GRAY, 20));
setPreferredSize(new Dimension(300, 250));
add(new FocusableComponent1(), Color.RED, new Dimension(200, 20));
add(new FocusableComponent1(), Color.GREEN, new Dimension(50, 70));
add(new FocusableComponent2(), Color.GRAY, new Dimension(90, 100));
add(new FocusableComponent2(), Color.MAGENTA, new Dimension(80, 150));
}
private void add(final FocusableComponent fc, final Color fgColor, final Dimension size) {
add(fc);
fc.setForeground(fgColor);
fc.setSize(size);
}
}
public static void main(final String[] args) {
final JFrame frame = new JFrame("Focused Paint Comps");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new YourPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Update's "RandomLayout":
And the custom LayoutManager itself with JavaDoc (may be big, but reusable hopefully):
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.util.Random;
/**
* A {#link java.awt.LayoutManager} which lays out randomly all the {#link java.awt.Component}s
* of its parent, taking into consideration the parent's {#link java.awt.Insets}.
* <p>
* Use {#link #setRandomizeOnce(boolean)} method to determine if the lastly laid-out parent will
* be only laid-out randomly once and not for each {#link #layoutContainer(java.awt.Container)}
* subsequent call for the same parent, or the opposite.
* </p>
*/
public class RandomLayout implements LayoutManager {
/**
* The {#link java.awt.Container} which was lastly laid-out.
*/
private Container lastParent;
/**
* The {#link java.awt.Insets} of {#code lastParent} the last time it was laid-out.
*/
private Insets lastInsets;
/**
* If {#code true} then this {#link java.awt.LayoutManager} keeps track of the
* {#link java.awt.Container}s laid-out to make sure that {#code lastParent} is
* only laid-out once. If the another {#link java.awt.Container} is laid-out, other
* than {#code lastParent}, then its components are laid-out randomly and the
* {#link java.awt.Container} becomes the {#code lastParent}.
*/
private boolean randomizeOnce;
/**
* Normal constructor of {#code RandomLayout} with explicit value for {#code randomizeOnce}.
*
* #param randomizeOnce {#code true} if the lastly laid-out parent will be only laid-out
* randomly once and not for each {#link #layoutContainer(java.awt.Container)} subsequent call
* for the same parent, otherwise {#code false} and each call to
* {#link #layoutContainer(java.awt.Container)} will lay out randomly the {#link java.awt.Container}.
*/
public RandomLayout(final boolean randomizeOnce) {
this.randomizeOnce = randomizeOnce;
}
/**
* Default constructor of {#code RandomLayout} with {#code randomizeOnce} set to {#code true}.
*/
public RandomLayout() {
this(true);
}
/**
* If {#code true} then this {#link java.awt.LayoutManager} keeps track of the
* {#link java.awt.Container}s laid-out to make sure that {#code lastParent} is
* only laid-out once. If the another {#link java.awt.Container} is laid-out, other
* than {#code lastParent}, then its components are laid-out randomly and the
* {#link java.awt.Container} becomes the {#code lastParent}.
*
* #param randomizeOnce {#code true} if the lastly laid-out parent will be only laid-out
* randomly once and not for each {#link #layoutContainer(java.awt.Container)} subsequent call
* for the same parent, otherwise {#code false}.
*/
public void setRandomizeOnce(final boolean randomizeOnce) {
this.randomizeOnce = randomizeOnce;
}
/**
* Tells if the lastly laid-out parent will be only laid-out randomly once and not for each
* {#link #layoutContainer(java.awt.Container)} subsequent call for the same parent, or the
* opposite.
*
* #return {#code true} if the lastly laid-out parent will be only laid-out randomly once and
* not for each {#link #layoutContainer(java.awt.Container)} subsequent call for the same
* parent, otherwise {#code false}.
*/
public boolean isRandomizeOnce() {
return randomizeOnce;
}
/**
* #return The {#link java.awt.Container} which was lastly laid-out.
*/
protected Container getLastParent() {
return lastParent;
}
/**
* #return The {#link java.awt.Insets} of {#code lastParent} the last time it was laid-out.
* #see #getLastParent()
*/
protected Insets getLastInsets() {
return lastInsets;
}
/**
* Adds the specified component with the specified name to the layout.
* #param name The name of the component.
* #param comp The {#link java.awt.Component} to be added.
*/
public void addLayoutComponent(final String name,
final Component comp) {
}
/**
* Removes the specified component from the layout.
* #param comp The {#link java.awt.Component} to be removed.
*/
public void removeLayoutComponent(final Component comp) {
}
/**
* {#inheritDoc}
* #return The preferred size dimensions for the specified {#link java.awt.Container}.
*/
#Override
public Dimension preferredLayoutSize(final Container parent) {
final Dimension prefDim = minimumLayoutSize(parent);
prefDim.width += 2; //+2 to spare.
prefDim.height += 2; //+2 to spare.
return prefDim;
}
/**
* {#inheritDoc}
* #return The minimum size dimensions for the specified {#link java.awt.Container}.
*/
#Override
public Dimension minimumLayoutSize(final Container parent) {
final Dimension minDim = new Dimension();
final int childCnt = parent.getComponentCount();
for (int i=0; i<childCnt; ++i)
applyBigger(minDim, getPreferredSize(parent, parent.getComponent(i)));
final Insets parInsets = parent.getInsets();
minDim.width += (parInsets.left + parInsets.right);
minDim.height += (parInsets.top + parInsets.bottom);
return minDim;
}
/**
* {#inheritDoc}. If the another {#link java.awt.Container} is laid-out, other
* than {#code lastParent}, then its components are laid-out randomly and the
* {#link java.awt.Container} becomes the {#code lastParent}.
*/
#Override
public void layoutContainer(final Container parent) {
if (parent == null)
throw new IllegalArgumentException("Cannot lay out null.");
if (isRandomizeOnce() && lastParent == parent) { //At least take care of insets (if they have changed).
final Insets parentInsets = parent.getInsets();
if (!lastInsets.equals(parentInsets)) {
final int offx = parentInsets.left - lastInsets.left,
offy = parentInsets.top - lastInsets.top;
final int childCnt = parent.getComponentCount();
for (int i=0; i<childCnt; ++i) {
final Component child = parent.getComponent(i);
final Point childLoca = child.getLocation();
childLoca.x += offx;
childLoca.y += offy;
child.setLocation(childLoca);
}
lastInsets = parentInsets;
}
}
else
layoutContainerRandomly(parent);
}
/**
* Explicitly lays out randomly the specified container.
* <p>
* This is equivalent of calling:
* <pre>
* boolean isRand1 = randomLayout.isRandomizeOnce();
* randomLayout.setRandomizeOnce(false);
* randomLayout.layoutContainer(parent);
* randomLayout.setRandomizeOnce(isRand1);
* </pre>
* {#code parent} becomes {#code lastParent}.
* </p>
* #param parent The container to be laid out.
*/
public void layoutContainerRandomly(final Container parent) { //Place each child at a random location for the "new" parent (lastParent != parent).
if (parent == null)
throw new IllegalArgumentException("Cannot lay out null.");
reset();
final Dimension parentSize = parent.getSize();
final Insets parentInsets = parent.getInsets();
final Dimension childSize = new Dimension();
final Point childLoca = new Point();
final Random rand = new Random();
final int childCnt = parent.getComponentCount();
for (int i=0; i<childCnt; ++i) {
final Component child = parent.getComponent(i);
child.getSize(childSize);
childLoca.x = parentInsets.left + 1;
childLoca.y = parentInsets.top + 1;
final int xBound = parentSize.width - parentInsets.left - parentInsets.right - childSize.width,
yBound = parentSize.height - parentInsets.top - parentInsets.bottom - childSize.height;
if (xBound > 0)
childLoca.x += rand.nextInt(xBound);
if (yBound > 0)
childLoca.y += rand.nextInt(yBound);
child.setLocation(childLoca);
}
lastParent = parent;
lastInsets = parentInsets;
}
/**
* Invalidates the tracking of the lastly laid-out {#link java.awt.Container} and its last
* {#link java.awt.Insets}.
* #see #getLastParent()
* #see #getLastInsets()
*/
protected void reset() {
lastParent = null;
lastInsets = null;
}
private static void applyBigger(final Dimension inputOutput,
final Dimension input) {
if (inputOutput != null && input != null) {
inputOutput.width = (int) Math.max(inputOutput.width, input.width);
inputOutput.height = (int) Math.max(inputOutput.height, input.height);
}
}
private static void applyIfBetter(final Dimension inputOutput,
final Dimension input) {
if (inputOutput != null && input != null
&& (input.width > inputOutput.width
|| input.height > inputOutput.height)) {
inputOutput.width = input.width;
inputOutput.height = input.height;
}
}
/**
* Tries to determine the best size for {#code child}.
* #param parnt The parent {#link java.awt.Container} being laid-out.
* #param child The child {#link java.awt.Component} of {#code parnt} being laid-out.
* #return A preferred size for the {#code child} to be laid-out.
*/
protected static Dimension getPreferredSize(final Container parnt,
final Component child) {
final Dimension minDim = new Dimension();
if (child != null) {
applyIfBetter(minDim, child.getMinimumSize());
applyIfBetter(minDim, child.getSize());
applyIfBetter(minDim, child.getPreferredSize());
}
return minDim;
}
}
Updated screenshot:
And here is the new screenshot (no big visual differences):
Note for the update:
Be aware that this is my first custom LayoutManager, but I have read the documentation, and also GridLayout and SpringLayout as examples (because, in my oppinion, LayoutManager's documentation is not enough) and of course I tested it. As it is wright now, I cannot find any problem with it. Any suggestions or proposals for improvements will be appreciated of course.
I'm trying to paint a dynamic graph that has a few thousand points. I'm using SwingWorker class that gets the Graphics object as an argument. I initialize the graphics object in the constructor of the SwingWorker class and then call the main graphing function doGraph() in the done() method i.e, after all the calculations are done. I'm having issues with painting, not sure what is going on. The code works if I call doGraph() from the constructor of the SwingWorker class but not when I place it in done().
Any help is greatly appreciated. I have simplified the code for ease of understanding. I`m just trying to paint a rectangle in the doGraph() for simplicity.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.RenderingHints.Key;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
#SuppressWarnings("serial")
public class UIGraph extends JPanel {
private double minX, maxX;
private double minY, maxY;
private SWPaint swPaint; //Swing Worker object
private Graphics2D g2D;
public Key key = RenderingHints.KEY_ANTIALIASING;
public Object obj = RenderingHints.VALUE_ANTIALIAS_ON;
private int labelPadding = 25;
private int padding = 25;
private int padConst = (2 * padding) - labelPadding;
private double xScale;
private double yScale;
/**
* Crate Panel
*/
private void createUI() {
setBackground(new Color(245, 255, 250));
setLayout(new BorderLayout(0, 0));
}
/**
* Constructor
*
*/
public UIGraph() {
createUI();
getMinMax();
}
/**
* Paint Component. Do all the calculations and graphing
*/
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (swPaint != null) {
if (!swPaint.isDone()) { // The swing worker is busy with tasks. Set Visibility to false and return.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setVisible(false);
}
});
return;
}
}
swPaint = new SWPaint(g); //Create a swing worker class, pass graphics object as argument
swPaint.execute();
}
}
/**
* Get the Min and Max values of Data
*/
private void getMinMax() {
//obtain min and max values
}
/**
* Main method for graphing
*
* #param g2D
*/
private void doGraph() {
xScale = (double) (getWidth() - padConst) / (maxX - minX);
yScale = (double) (getHeight() - padConst) / (maxY - minY);
g2D.setColor(Color.WHITE);
g2D.fillRect(padding + labelPadding, padding, getWidth() - (2 * padding) - labelPadding, getHeight() - 2 * padding
- labelPadding);
g2D.setColor(Color.BLACK);
}
/**
* Swing Worker to handle Paint
*
*/
public class SWPaint extends SwingWorker<Void, Void> {
/**
* Constructor
*
* #param g
*/
public SWPaint(Graphics g) {
g2D = (Graphics2D) g;
g2D.setRenderingHint(key, obj);
//doGraph() //This works
}
/**
* Do graphing calculations here
*/
#Override
protected Void doInBackground() throws Exception {
// do all calculations here
return null;
}
/*
* The SW is done. Paint the graph. Set Visibility to true
*/
protected void done() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
doGraph(); //This doesn`t work here.
setVisible(true);
}
});
}
}
}
im using the Canvas class to make a screensaver as a schoolproject.
But the window generated by Canvas doesnt show my objects on it (current time)
until i minimize it an resize it again. After that all things works fine.
so what is wrong?
thank you for coming answers!
with kind regards
leon
those are the classes, i peronally think that the problem is in the class Start or BufferedCanvas
import java.awt.*;
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class Start
{
int fensterX = 900;
int fensterY = 700;
Farbengenerator fg = new Farbengenerator();
BufferedCanvas c =newBufferedCanvas("Bild",fensterX,fensterY);
Zeit z = new Zeit();
SchriftParameter sp = new SchriftParameter();
public void zeichneText(){
double x = 100;
double y = 100;
double fy =0.01;
double fx =0.02;
int red=0;
int green=0;
int blue=0;
double colourGrowRate=0.05;
String uhr;
c.setFont(sp.setzteSchrift());
c.setForegroundColour(Color.BLACK);
c.setBackgroundColour(Color.WHITE);
for(int i=0;i<100;i++){
c.drawString("Starting...",(int)x,(int)y);
c.updateAndShow();
try{Thread.sleep(50);}
catch(Exception e){};
c.updateAndShow();
}
CreateButton d = new CreateButton();
d.run();
while(true) {
c.erase();
uhr = z.erstelleZeit();
c.drawString(uhr,(int)x,(int)y);
if((int)x >fensterX-93 || (int)x <5){
fx = fx * (-1);
red=fg.gibROT();
green=fg.gibGRUEN();
blue=fg.gibBLAU();
Color colour = new Color(red,green,blue);
c.setForegroundColour(colour);
}
if((int)y > fensterY-1 || (int)y < 46){
fy = fy * (-1);
red=fg.gibROT();
green=fg.gibGRUEN();
blue=fg.gibBLAU();
Color colour = new Color(red,green,blue);
c.setForegroundColour(colour);
}
if((int)colourGrowRate>=1){
fg.generiereFarbe();
colourGrowRate = 0.05;
}
colourGrowRate=colourGrowRate+colourGrowRate;
x = x + fx;
y = y + fy;
c.updateAndShow();
}
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
public class BufferedCanvas
{
private JFrame frame;
private CanvasPane canvas;
private Graphics2D graphic;
private Color backgroundColour;
private Image canvasImage;
BufferStrategy buff;
/**
* Create a BufferedCanvas with default height,
width and background colour
* (300, 300, white).
* #param title title to appear in Canvas Frame
*/
public BufferedCanvas(String title)
{
this(title, 300, 300, Color.white);
}
/**
* Create a BufferedCanvas with default background colour (white).
* #param title title to appear in Canvas Frame
* #param width the desired width for the canvas
* #param height the desired height for the canvas
*/
public BufferedCanvas(String title, int width, int height)
{
this(title, width, height, Color.white);
}
/**
* Create a BufferedCanvas.
* #param title title to appear in Canvas Frame
* #param width the desired width for the canvas
* #param height the desired height for the canvas
* #param bgClour the desired background colour of the canvas
*/
public BufferedCanvas(String title, int width, int height, Color bgColour)
{
frame = new JFrame();
canvas = new CanvasPane();
frame.setContentPane(canvas);
frame.setTitle(title);
canvas.setPreferredSize(new Dimension(width, height));
backgroundColour = bgColour;
frame.pack();
frame.createBufferStrategy(2);
buff = frame.getBufferStrategy();
graphic = (Graphics2D)buff.getDrawGraphics();
setVisible(true);
}
/**
* Set the canvas visibility and brings canvas to the front of screen
* when made visible. This method can also be used to bring an already
* visible canvas to the front of other windows.
* #param visible boolean value representing the desired visibility of
* the canvas (true or false)
*/
public void setVisible(boolean visible)
{
if(graphic == null) {
// first time: instantiate the offscreen image and fill it with
// the background colour
Dimension size = canvas.getSize();
canvasImage = canvas.createImage(size.width, size.height);
graphic = (Graphics2D)canvasImage.getGraphics();
graphic.setColor(backgroundColour);
graphic.fillRect(0, 0, size.width, size.height);
graphic.setColor(Color.black);
}
frame.setVisible(true);
}
/**
* Update the canvas and show the new image.
*/
public void updateAndShow(){
buff.show();
}
/**
* Provide information on visibility of the Canvas.
* #return true if canvas is visible, false otherwise
*/
public boolean isVisible()
{
return frame.isVisible();
}
/**
* Draw a given shape onto the canvas.
* #param shape the shape object to be drawn on the canvas
*/
public void draw(Shape shape)
{
graphic.draw(shape);
//canvas.repaint();
}
/**
* Fill the internal dimensions of a given shape with the current
* foreground colour of the canvas.
* #param shape the shape object to be filled
*/
public void fill(Shape shape)
{
graphic.fill(shape);
//canvas.repaint();
}
/**
* Erase the whole canvas.
*/
public void erase()
{
Color original = graphic.getColor();
graphic.setColor(backgroundColour);
Dimension size = canvas.getSize();
graphic.fill(new Rectangle(0, 0, size.width, size.height));
graphic.setColor(original);
//canvas.repaint();
}
/**
* Erase a given shape's interior on the screen.
* #param shape the shape object to be erased
*/
public void erase(Shape shape)
{
Color original = graphic.getColor();
graphic.setColor(backgroundColour);
graphic.fill(shape); // erase by filling background colour
graphic.setColor(original);
//canvas.repaint();
}
/**
* Erases a given shape's outline on the screen.
* #param shape the shape object to be erased
*/
public void eraseOutline(Shape shape)
{
Color original = graphic.getColor();
graphic.setColor(backgroundColour);
graphic.draw(shape); // erase by drawing background colour
graphic.setColor(original);
//canvas.repaint();
}
/**
* Draws an image onto the canvas.
* #param image the Image object to be displayed
* #param x x co-ordinate for Image placement
* #param y y co-ordinate for Image placement
* #return returns boolean value representing whether the image was
* completely loaded
*/
public boolean drawImage(Image image, int x, int y)
{
boolean result = graphic.drawImage(image, x, y, null);
//canvas.repaint();
return result;
}
/**
* Draws a String on the Canvas.
* #param text the String to be displayed
* #param x x co-ordinate for text placement
* #param y y co-ordinate for text placement
*/
public void drawString(String text, int x, int y)
{
graphic.drawString(text, x, y);
//canvas.repaint();
}
/**
* Erases a String on the Canvas.
* #param text the String to be displayed
* #param x x co-ordinate for text placement
* #param y y co-ordinate for text placement
*/
public void eraseString(String text, int x, int y)
{
Color original = graphic.getColor();
graphic.setColor(backgroundColour);
graphic.drawString(text, x, y);
graphic.setColor(original);
//canvas.repaint();
}
/**
* Draws a line on the Canvas.
* #param x1 x co-ordinate of start of line
* #param y1 y co-ordinate of start of line
* #param x2 x co-ordinate of end of line
* #param y2 y co-ordinate of end of line
*/
public void drawLine(int x1, int y1, int x2, int y2)
{
graphic.drawLine(x1, y1, x2, y2);
//canvas.repaint();
}
/**
* Draws a dot/pixel on the Canvas.
* #param x x co-ordinate of dot
* #param y y co-ordinate of dot
*/
public void drawDot(int x, int y)
{
graphic.drawLine(x, y, x, y);
//canvas.repaint();
}
/**
* Sets the foreground colour of the Canvas.
* #param newColour the new colour for the foreground of the Canvas
*/
public void setForegroundColour(Color newColour)
{
graphic.setColor(newColour);
}
/**
* Returns the current colour of the foreground.
* #return the colour of the foreground of the Canvas
*/
public Color getForegroundColour()
{
return graphic.getColor();
}
/**
* Sets the background colour of the Canvas.
* #param newColour the new colour for the background of the Canvas
*/
public void setBackgroundColour(Color newColour)
{
backgroundColour = newColour;
graphic.setBackground(newColour);
}
/**
* Returns the current colour of the background
* #return the colour of the background of the Canvas
*/
public Color getBackgroundColour()
{
return backgroundColour;
}
/**
* changes the current Font used on the Canvas
* #param newFont new font to be used for String output
*/
public void setFont(Font newFont)
{
graphic.setFont(newFont);
}
/**
* Returns the current font of the canvas.
* #return the font currently in use
**/
public Font getFont()
{
return graphic.getFont();
}
/**
* Sets the size of the canvas.
* #param width new width
* #param height new height
*/
public void setSize(int width, int height)
{
canvas.setPreferredSize(new Dimension(width, height));
Image oldImage = canvasImage;
canvasImage = canvas.createImage(width, height);
graphic = (Graphics2D)canvasImage.getGraphics();
graphic.drawImage(oldImage, 0, 0, null);
frame.pack();
}
/**
* Returns the size of the canvas.
* #return The current dimension of the canvas
*/
public Dimension getSize()
{
return canvas.getSize();
}
/**
* Waits for a specified number of milliseconds before finishing.
* This provides an easy way to specify a small delay which can be
* used when producing animations.
* #param milliseconds the number
*/
public void wait(int milliseconds)
{
try
{
Thread.sleep(milliseconds);
}
catch (Exception e)
{
// ignoring exception at the moment
}
}
/************************************************************************
* Nested class CanvasPane - the actual canvas component contained in the
* Canvas frame. This is essentially a JPanel with added capability to
* refresh the image drawn on it.
*/
private class CanvasPane extends JPanel
{
public void paint(Graphics g)
{
g.drawImage(canvasImage, 0, 0, null);
}
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
public class CreateButton extends JFrame implements ActionListener{
public void run() {
createAndShowGUI();
}
public CreateButton() {
// set layout for the frame
this.getContentPane().setLayout(new FlowLayout());
JButton button1 = new JButton();
button1.setText("closeApp");
//set actionlisteners for the buttons
button1.addActionListener(this);
// define a custom short action command for the button
button1.setActionCommand("closeApp");
// add buttons to frame
add(button1);
}
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new CreateButton();
//Display the window.
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent ae) {
String action = ae.getActionCommand();
if (action.equals("closeApp")) {
System.exit(1);
}
}
}
import java.awt.*;
public class SchriftParameter
{
public Font setzteSchrift(){
Font f = new Font("Fixed",1,24);
return (f);
}
}
public class Farbengenerator
{
int r=0;
int g=0;
int b=0;
public void generiereFarbe(){
if (r<255&&g==0&&b==0){
r++;
}
else if (r==255&&g<255&&b==0){
g++;
}
else if (r>0&&g==255&&b==0){
r= r-1;
}
else if (r==0&&g==255&&b<255){
b++;
}
else if (r==0&&g>0&&b==255){
g=g-1;
}
else if (r<255&&g==0&&b==255){
r++;
}
else if (r==255&&g==0&&b>0){
b=b-1;
}
}
public int gibROT () {
return(r);
}
public int gibGRUEN () {
return(g);
}
public int gibBLAU () {
return(b);
}
}
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class Zeit
{
public String erstelleZeit(){
DateFormat df = new SimpleDateFormat("HH:mm:ss");
Date d = new Date();
String uhr = df.format(d);
return (uhr);
}
}
I'm sure, this is something like a super stupid standard problem, but I spent hours searching and trying to get this fixed, but it just won't work... I just can't find my mistake here...
I'm trying to build a simple program that prints something on a JComponent. The paintComponent()-Method refers to some variables and I want the JComponent ONLY to repaint, if i say so! But it always repaints whenever i change the variables...
Heres the code of my 2 classes:
import java.awt.Dimension;
import javax.swing.*;
public class SimplePaint extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private PaintingCanvas pc;
public SimplePaint() {
super("SimplePaint");
this.pc = new PaintingCanvas();
this.pc.setPreferredSize(new Dimension(800, 600));
this.add(pc);
this.setResizable(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
this.setVisible(true);
this.setLocationRelativeTo(null);
}
public static void main(String[] args) {
SimplePaint sp = new SimplePaint();
sp.pc.setxStart(50);
sp.pc.setyStart(60);
sp.pc.setxEnd(140);
sp.pc.setyEnd(300);
}
}
and
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.*;
public class PaintingCanvas extends JComponent {
/**
*
*/
private static final long serialVersionUID = 1L;
private int xStart, yStart;
private int xEnd, yEnd;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.fillRect(xStart, yStart, xEnd, yEnd);
}
/**
* #param xStart the xStart to set
*/
public void setxStart(int xStart) {
this.xStart = xStart;
}
/**
* #param yStart the yStart to set
*/
public void setyStart(int yStart) {
this.yStart = yStart;
}
/**
* #param xEnd the xEnd to set
*/
public void setxEnd(int xEnd) {
this.xEnd = xEnd;
}
/**
* #param yEnd the yEnd to set
*/
public void setyEnd(int yEnd) {
this.yEnd = yEnd;
}
}
What it displays: The Canvas with a rectangle (50, 60, 140, 300)...
What is should display: The blank canvas, and if i then put sp.pc.repaint() or something like that in the main method, it should repaint and therefore show the rectangle...
You cannot make any assumption on when and how many times paintComponent will be called. When making the frame visible, it wille be invoked. If you maximize your frame also, etc... There are many situations when paintComponent will be invoked.
The solution is pretty easy:
Add a flag (boolean drawRectangle = false;) on your PaintingCanvas class
In paintComponent check the value of the flag and draw (or not) the rectangle accordingly
When you want the rectangle to appear, toggle the value of the flag