OK, i've been searching and googling for ages and it's driving me MAD. (please bear in mind this started as code from the University).
Any help would be massively appreciated! Since I appear to have a mental block when it comes to java graphics :(.
The problem is to label an image however i'm having issues with half of the image being lost for various reasons unless I move around the frame and then it comes back. Likewise if I try to remove 'labels' which are painted on the BufferedImage, I have to move around the Jframe in order to see the result.
Lastly, when the JOptionPane pops up to ask for a label name, it does this when closed:
getting an image to post
https://docs.google.com/document/d/1I5rFH23a75IHB6twTu1dPRwmRt-By1sIUvDvI6FE_OY/edit
package hci;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Deals with the label tools
*/
public class LabelToolGUI extends JPanel implements ActionListener {
JButton newButton = new JButton("New");
JButton deleteButton = new JButton("Delete");
JButton editButton = new JButton("Edit");
JButton undoButton = new JButton("Undo");
JComboBox labelsBox = new JComboBox();
String saveIcon = "./images/icons/save.jpg";
String deleteIcon = "./images/icons/delete.jpg";
String openIcon = "./images/icons/open.jpg";
String newIcon = "./images/icons/new.jpg";
String helpIcon = "./images/icons/help.jpg";
String labelsIcon = "./images/icons/help.jpg";
String fname = "";
String fnameURL = "";
public LabelToolGUI() {
super();
newButton.addActionListener(this);
deleteButton.addActionListener(this);
editButton.addActionListener(this);
undoButton.addActionListener(this);
setLayout(new BorderLayout());
setBorder(BorderFactory.createTitledBorder("Label tools"));
add(newButton, BorderLayout.WEST);
add(deleteButton, BorderLayout.EAST);
add(editButton, BorderLayout.CENTER);
add(labelsBox, BorderLayout.NORTH);
add(undoButton, BorderLayout.SOUTH);
}
#Override
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
if(src == newButton) {
String labelName = JOptionPane.showInputDialog("Please input a value");
ImageLabeller.addNewPolygon(labelName);
labelsBox.addItem(labelName);
} else if(src == deleteButton) {
String toDelete = labelsBox.getSelectedItem().toString();
System.out.println("Deleting " + toDelete);
labelsBox.removeItem(labelsBox.getSelectedItem());
ImageLabeller.removeLabel(toDelete);
} else if(src == undoButton) {
ImageLabeller.undo();
ImageLabeller.imagePanel.repaint();
}
}
}
package hci;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/**
* Main class of the program - handles display of the main window
* #author Michal
*
*/
public class ImageLabeller extends JFrame implements ActionListener {
/**
* some java stuff to get rid of warnings
*/
private static final long serialVersionUID = 1L;
/**
* main window panel
*/
JPanel appPanel = null;
/**
* toolbox - put all buttons and stuff here!
*/
JPanel toolboxPanel = null;
/**
* image panel - displays image and editing area
*/
static ImagePanel imagePanel = null;
/**
* handles New Object button action
*/
public static void addNewPolygon(String labelName) {
imagePanel.addNewPolygon(labelName);
}
public static void removeLabel(String labelName) {
LabelHandler.deleteLabel(labelName);
}
/**
* Removes last point added to the label.
*/
public static void undo() {
imagePanel.currentLabel.removeLast();
}
/*#Override
public void paint(Graphics g) {
super.paint(g);
imagePanel.paint(g); //update image panel
} */
/**
* sets up application window
* #param imageFilename image to be loaded for editing
* #throws Exception
*/
public void setupGUI(String imageFilename) throws Exception {
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent event) {
//here we exit the program (maybe we should ask if the user really wants to do it?)
//maybe we also want to store the polygons somewhere? and read them next time
System.out.println("Bye bye!");
System.exit(0);
}
});
//setup main window panel
appPanel = new JPanel();
this.setLayout(new BoxLayout(appPanel, BoxLayout.X_AXIS));
this.setContentPane(appPanel);
//Create and set up the image panel.
imagePanel = new ImagePanel(imageFilename);
imagePanel.setOpaque(true); //content panes must be opaque
appPanel.add(imagePanel);
//add toolbox to window
appPanel.add(new LabelToolGUI());
//display all the stuff
this.pack();
this.setVisible(true);
}
/**
* Runs the program
* #param argv path to an image
*/
public static void main(String argv[]) {
try {
//create a window and display the image
ImageLabeller window = new ImageLabeller();
window.setupGUI(argv[0]);
} catch (Exception e) {
System.err.println("Image: " + argv[0]);
e.printStackTrace();
}
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Action clicked");
imagePanel.paint(imagePanel.getGraphics());
}
}
package hci;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import hci.utils.*;
/**
* Handles image editing panel
* #author Michal
*
*/
public class ImagePanel extends JPanel implements MouseListener {
/**
* some java stuff to get rid of warnings
*/
private static final long serialVersionUID = 1L;
/**
* image to be tagged
*/
BufferedImage image = null;
/**
* list of current polygon's vertices
*/
Label currentLabel = null;
/**
* default constructor, sets up the window properties
*/
public ImagePanel() {
currentLabel = new Label();
this.setVisible(true);
Dimension panelSize = new Dimension(800, 600);
this.setSize(panelSize);
this.setMinimumSize(panelSize);
this.setPreferredSize(panelSize);
this.setMaximumSize(panelSize);
addMouseListener(this);
}
/**
* extended constructor - loads image to be labelled
* #param imageName - path to image
* #throws Exception if error loading the image
*/
public ImagePanel(String imageName) throws Exception{
this();
image = ImageIO.read(new File(imageName));
if (image.getWidth() > 800 || image.getHeight() > 600) {
int newWidth = image.getWidth() > 800 ? 800 : (image.getWidth() * 600)/image.getHeight();
int newHeight = image.getHeight() > 600 ? 600 : (image.getHeight() * 800)/image.getWidth();
System.out.println("SCALING TO " + newWidth + "x" + newHeight );
Image scaledImage = image.getScaledInstance(newWidth, newHeight, Image.SCALE_FAST);
image = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
image.getGraphics().drawImage(scaledImage, 0, 0, this);
}
}
/**
* Displays the image
*/
public void ShowImage() {
Graphics g = this.getGraphics();
if (image != null) {
g.drawImage(image, 0, 0, null);
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
//display iamge
ShowImage();
//display all the completed polygons
for(Label l : LabelHandler.labels) {
drawLabel(l);
finishPolygon(l);
}
//display current polygon
drawLabel(currentLabel);
}
/**
* displays a polygon without last stroke
* #param l label to be displayed
*/
public void drawLabel(Label l) {
Graphics2D g = (Graphics2D)this.getGraphics();
g.setColor(Color.GREEN);
for(int i = 0; i < l.size(); i++) {
Point currentVertex = l.getPoint(i);
if (i != 0) {
Point prevVertex = l.getPoint(i - 1);
g.drawLine(prevVertex.getX(), prevVertex.getY(), currentVertex.getX(), currentVertex.getY());
}
g.fillOval(currentVertex.getX() - 5, currentVertex.getY() - 5, 10, 10);
}
}
/**
* displays last stroke of the polygon (arch between the last and first vertices)
* #param l label to be finished
*/
public void finishPolygon(Label l) {
//if there are less than 3 vertices than nothing to be completed
if (l.size() >= 3) {
Point firstVertex = l.getPoint(0);
Point lastVertex = l.getPoint(l.size() - 1);
Graphics2D g = (Graphics2D)this.getGraphics();
g.setColor(Color.GREEN);
g.drawLine(firstVertex.getX(), firstVertex.getY(), lastVertex.getX(), lastVertex.getY());
}
}
/**
* moves current polygon to the list of polygons and makes pace for a new one
*/
public void addNewPolygon(String labelName) {
//finish the current polygon if any
if (currentLabel != null ) {
finishPolygon(currentLabel);
LabelHandler.addLabel(currentLabel);
}
currentLabel = new Label(labelName);
}
#Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
//check if the cursos withing image area
if (x > image.getWidth() || y > image.getHeight()) {
//if not do nothing
return;
}
Graphics2D g = (Graphics2D)this.getGraphics();
//if the left button than we will add a vertex to poly
if (e.getButton() == MouseEvent.BUTTON1) {
g.setColor(Color.GREEN);
if (currentLabel.size() != 0) {
Point lastVertex = currentLabel.getPoint(currentLabel.size() - 1);
g.drawLine(lastVertex.getX(), lastVertex.getY(), x, y);
}
g.fillOval(x-5,y-5,10,10);
currentLabel.addPoint(new Point(x,y));
System.out.println(x + " " + y);
}
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
Don't use getGraphics() for your painting, as it is temporary buffer which is recycled on next repaint. Do you painting in paintComponent() and call repaint() if needed.
Also don't call paint() manually (ie: imagePanel.paint(imagePanel.getGraphics());)
See Performing Custom Painting for more information. Also see Painting in AWT and Swing.
In ImagePanel.paintComponent replace ShowImage(); by if (image != null) g.drawImage( image, 0, 0, this );.
The device context g is initialized by swing, you don"t have to obtain another by getGraphics().
Related
I created a graphical component that allows you to view an image and allows you to make a selection of a part of the image: the selection of a portion of the image is accomplished by drawing a rectangle on this image (using drag-and-drop).
To this purpose, I used this example, which created a subclass of JLabel in order to draw the image and in order to deal with the drawing of the rectangle. Then I put an instance of this subclass within a JPanel, in order to have the image always positioned at the center of the panel.
FigurePanel.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.MouseInputAdapter;
public class FigurePanel extends JPanel
{
private SelectionLabel imageLabel = null;
public FigurePanel()
{
this.setLayout(new GridBagLayout());
imageLabel = new SelectionLabel();
this.add(imageLabel, null);
}
public void setImage(Image image)
{
imageLabel.setImage(image);
}
private class SelectionLabel extends JLabel
{
private Rectangle currentRect = null;
private Rectangle rectToDraw = null;
private final Rectangle previousRectDrawn = new Rectangle();
public SelectionLabel()
{
super();
setOpaque(true);
SelectionListener listener = new SelectionListener();
addMouseListener(listener);
addMouseMotionListener(listener);
}
public void setImage(Image image)
{
currentRect = null;
rectToDraw = null;
previousRectDrawn.setBounds(0, 0, 0, 0);
setIcon(new ImageIcon(image));
}
private class SelectionListener extends MouseInputAdapter
{
#Override
public void mousePressed(MouseEvent e)
{
int x = e.getX();
int y = e.getY();
currentRect = new Rectangle(x, y, 0, 0);
updateDrawableRect(getWidth(), getHeight());
repaint();
}
#Override
public void mouseDragged(MouseEvent e)
{
updateSize(e);
}
#Override
public void mouseReleased(MouseEvent e)
{
updateSize(e);
}
/*
* Update the size of the current rectangle
* and call repaint. Because currentRect
* always has the same origin, translate it
* if the width or height is negative.
*
* For efficiency (though
* that isn't an issue for this program),
* specify the painting region using arguments
* to the repaint() call.
*
*/
void updateSize(MouseEvent e)
{
int x = e.getX();
int y = e.getY();
currentRect.setSize(x - currentRect.x,
y - currentRect.y);
updateDrawableRect(getWidth(), getHeight());
Rectangle totalRepaint = rectToDraw.union(previousRectDrawn);
repaint(totalRepaint.x, totalRepaint.y,
totalRepaint.width, totalRepaint.height);
}
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g); //paints the background and image
//If currentRect exists, paint a box on top.
if (currentRect != null) {
//Draw a rectangle on top of the image.
g.setXORMode(Color.white); //Color of line varies
//depending on image colors
g.drawRect(rectToDraw.x, rectToDraw.y,
rectToDraw.width - 1, rectToDraw.height - 1);
System.out.println("rectToDraw: " + rectToDraw);
}
}
private void updateDrawableRect(int compWidth, int compHeight)
{
int x = currentRect.x;
int y = currentRect.y;
int width = currentRect.width;
int height = currentRect.height;
//Make the width and height positive, if necessary.
if (width < 0) {
width = 0 - width;
x = x - width + 1;
if (x < 0) {
width += x;
x = 0;
}
}
if (height < 0) {
height = 0 - height;
y = y - height + 1;
if (y < 0) {
height += y;
y = 0;
}
}
//The rectangle shouldn't extend past the drawing area.
if ((x + width) > compWidth) {
width = compWidth - x;
}
if ((y + height) > compHeight) {
height = compHeight - y;
}
//Update rectToDraw after saving old value.
if (rectToDraw != null) {
previousRectDrawn.setBounds(
rectToDraw.x, rectToDraw.y,
rectToDraw.width, rectToDraw.height);
rectToDraw.setBounds(x, y, width, height);
} else {
rectToDraw = new Rectangle(x, y, width, height);
}
}
}
}
FigurePanelTest.java
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
public class FigurePanelTest extends JFrame
{
public FigurePanelTest()
{
FigurePanel imagePanel = new FigurePanel();
JScrollPane imageScrollPane = new JScrollPane();
imageScrollPane.setPreferredSize(new Dimension(420, 250));
imageScrollPane.setViewportView(imagePanel);
JButton imageButton = new JButton("Load Image");
imageButton.addActionListener(
new ActionListener()
{
#Override
public void actionPerformed(ActionEvent evt)
{
JFileChooser fc = new JFileChooser();
int returnValue = fc.showOpenDialog(null);
if (returnValue == JFileChooser.APPROVE_OPTION) {
File selectedFile = fc.getSelectedFile();
System.out.println(selectedFile.getName());
try
{
Image image = ImageIO.read(selectedFile.getAbsoluteFile());
imagePanel.setImage(image);
imageScrollPane.getViewport().setViewPosition(new Point(0, 0));
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
);
Container container = getContentPane();
container.setLayout(new BorderLayout());
container.add(imageScrollPane, BorderLayout.CENTER);
container.add(imageButton, BorderLayout.NORTH);
setSize(600, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new FigurePanelTest().setVisible(true);
}
});
}
}
The private class SelectionLabel is the class SelectionArea from this example.
When a new rectangle is drawn, a message is printed on the console. Now I would replace the printing of the message with the firing of a custom event, so that the position and size of the rectangle are accessible to the application business logic.
I read how to create a custom event in Java. Moreover, this article identifies two super types for creating events: EventObject and AWTEvent. This articles states:
Normally you extend AWTEvent for events generated by a graphical
component and EventObject any other time.
Since the event concerning the selection of a part of the image is generated by a graphical component (that is the FigurePanel panel), I could implement the ImageSelectionEvent class by extending AWTEvent, as the following code snippet.
public class ImageSelectionEvent extends AWTEvent
{
public ImageSelectionEvent(Object source, int id) {
super(source, id);
}
}
The documentation identifies the id as the event type. So, what value should be assigned to this parameter?
Moreover, why does the constructor of EventObject class be devoid of the id parameter?
When creating an event class, you must guarantee that the event is
immutable. The event generator will share the same event instance
among the listeners; so ensure any one listener cannot change the
event's state.
What about this?
I don't know what is needed to create a custom event.
However, since you are extending JLabel maybe you can just create a PropertyChangeEvent.
To generated the event you would just use something like:
firePropertyChange("selectionRectangle", oldRectangle, newRectangle);
Then you can use a PropertyChangeListener to listen for "selectionRectangle" changes.
The Javadoc for AWTEvent says:
Subclasses of this root AWTEvent class defined outside of the java.awt.event package should define event ID values greater than the value defined by RESERVED_ID_MAX.
This value is 1999. You can set it to whatever you want that's higher than that. This value is specified by all the different types of Swing events, and Swing uses values that are less than that. For example, the MouseEvent event types use values from 500-507.
The main thing is to use a consistent value for your events.
Finally, I would consider subclassing ComponentEvent over AWTEvent as the source of your event is a Component, not an Object.
in my application I have label which has a font size over 200. This label contains big up and down (irregular)gap. How can I remove it ?
This is my code:
package Core;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class LabelDemo extends JPanel {
public LabelDemo() {
super(new GridBagLayout());
JLabel label2;
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
// Create the other labels.
label2 = new JLabel("Text-Only Label");
label2.setBorder(BorderFactory.createTitledBorder("aaaaaaaa"));
label2.setFont(new Font("Verdana", Font.PLAIN, (int) 220));
// label2.setBorder(new EmptyBorder(-50, 0, 0, 0));
// Add the labels.
add(label2, c);
}
/**
* Create the GUI and show it. For thread safety, this method should be invoked from the event dispatch thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("LabelDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Add content to the window.
frame.add(new LabelDemo());
// Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event dispatch thread:
// creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Turn off metal's use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
I also try my last post: How to change gap in swing label and experiment with insets but this looks different in linux and windows
Is there some better way how to remove this gap ?
JDigit may give you some ideas:
It override's paintComponent() to down-sample a high-resolution BufferedImage and control the geometry.
It uses setBorderPainted(false) to set the borderPainted property.
It uses a FocusHandler for custom highlighting.
Addendum: As noted here, the underlying problem is the font's leading, defined in FontMetrics as being included in the font's height. As suggested in a comment by #Guillaume Polet, you can render the text wherever you want in your own JComponent. TextLayout, discussed here, can be used to calculate the bounds, as shown below.
Pros:
Absolute control over placement.
Geometry of TexteLayout bounds based on FontMetrics.
Cons:
No Icon support.
No HTML support.
Note that the JComponent authors "recommend that you put the component in a JPanel and set the border on the JPanel."
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* #see https://stackoverflow.com/a/16014525/230513
*/
public class UnleadedTest {
private static class Unleaded extends JComponent {
private Font font = new Font("Verdana", Font.PLAIN, 144);
private FontRenderContext frc = new FontRenderContext(null, true, true);
private String text;
private TextLayout layout;
private Rectangle r;
public Unleaded(String text) {
this.text = text;
calcBounds();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(r.width, r.height);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
calcBounds();
layout.draw(g2d, -r.x, -r.y);
}
private void calcBounds() {
layout = new TextLayout(text, font, frc);
r = layout.getPixelBounds(null, 0, 0);
}
}
private void display() {
JFrame f = new JFrame("Unleaded");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Unleaded label = new Unleaded("Unleaded");
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createTitledBorder("Title"));
panel.add(label);
f.add(panel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new UnleadedTest().display();
}
});
}
}
The "right way" to do this would be to extend "BasicLabelUI" and override the "protected String layoutCL()" method. This is the method that is responsible for laying out everything inside the label and is called when the "getPreferredSize()" of the JLabel is called. So this method determines the height the component is going to be.
If you drill down deep enough you'll see that the height is determined by the following line in the SwingUtilities:1021 class (which is used by layoutCL):
textR.height = fm.getHeight();
So the label is not causing the white space, the font is. The label just conforms to what the FontMetrics object says is the maximum height of the font for that size.
The easiest way would probably be to cheat; Force the size calculation to do something it shouldn't. Below is your example with a custom LabelUI component which you can experiment on. For example if you force the variable to 'dy' to '-40' the text will be at the top. If you want to make something more durable you could check all the leters in the string of the label, measure their maximum height and use that in the layoutCL method. But thats more work obviously.
package Core;
import sun.swing.SwingUtilities2;
import javax.swing.*;
import javax.swing.plaf.LabelUI;
import javax.swing.plaf.basic.BasicLabelUI;
import javax.swing.text.View;
import java.awt.*;
public class LabelDemo extends JPanel {
public LabelDemo() {
super(new GridBagLayout());
JLabel label2;
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
// Create the other labels.
label2 = new JLabel("Text-Only Label");
label2.setVerticalAlignment(SwingUtilities.TOP);
label2.setVerticalTextPosition(SwingUtilities.TOP);
label2.setUI(SkinnyLabelUI.createUI(label2));
label2.setBorder(BorderFactory.createTitledBorder("aaaaaaaa"));
label2.setFont(new Font("Verdana", Font.PLAIN, (int) 220));
// label2.setBorder(new EmptyBorder(-50, 0, 0, 0));
// Add the labels.
add(label2, c);
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event dispatch thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("LabelDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Add content to the window.
frame.add(new LabelDemo());
// Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event dispatch thread:
// creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Turn off metal's use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
private static class SkinnyLabelUI extends BasicLabelUI {
private static final SkinnyLabelUI labelUI = new SkinnyLabelUI();
public static LabelUI createUI(JComponent c) {
return labelUI;
}
protected String layoutCL(
JLabel label,
FontMetrics fm,
String text,
Icon icon,
Rectangle viewR,
Rectangle iconR,
Rectangle textR) {
int verticalAlignment = label.getVerticalAlignment();
int horizontalAlignment = label.getHorizontalAlignment();
int verticalTextPosition = label.getVerticalTextPosition();
int horizontalTextPosition = label.getHorizontalTextPosition();
if (icon != null) {
iconR.width = icon.getIconWidth();
iconR.height = icon.getIconHeight();
} else {
iconR.width = iconR.height = 0;
}
/* Initialize the text bounds rectangle textR. If a null
* or and empty String was specified we substitute "" here
* and use 0,0,0,0 for textR.
*/
boolean textIsEmpty = (text == null) || text.equals("");
int lsb = 0;
int rsb = 0;
/* Unless both text and icon are non-null, we effectively ignore
* the value of textIconGap.
*/
int gap;
View v;
if (textIsEmpty) {
textR.width = textR.height = 0;
text = "";
gap = 0;
} else {
int availTextWidth;
gap = (icon == null) ? 0 : label.getIconTextGap();
if (horizontalTextPosition == SwingUtilities.CENTER) {
availTextWidth = viewR.width;
} else {
availTextWidth = viewR.width - (iconR.width + gap);
}
v = (label != null) ? (View) label.getClientProperty("html") : null;
if (v != null) {
textR.width = Math.min(availTextWidth,
(int) v.getPreferredSpan(View.X_AXIS));
textR.height = (int) v.getPreferredSpan(View.Y_AXIS);
} else {
textR.width = SwingUtilities2.stringWidth(label, fm, text);
lsb = SwingUtilities2.getLeftSideBearing(label, fm, text);
if (lsb < 0) {
// If lsb is negative, add it to the width and later
// adjust the x location. This gives more space than is
// actually needed.
// This is done like this for two reasons:
// 1. If we set the width to the actual bounds all
// callers would have to account for negative lsb
// (pref size calculations ONLY look at width of
// textR)
// 2. You can do a drawString at the returned location
// and the text won't be clipped.
textR.width -= lsb;
}
if (textR.width > availTextWidth) {
text = SwingUtilities2.clipString(label, fm, text,
availTextWidth);
textR.width = SwingUtilities2.stringWidth(label, fm, text);
}
textR.height = fm.getHeight();
System.out.println("font height: " + textR.height);
}
}
/* Compute textR.x,y given the verticalTextPosition and
* horizontalTextPosition properties
*/
if (verticalTextPosition == SwingUtilities.TOP) {
if (horizontalTextPosition != SwingUtilities.CENTER) {
textR.y = 0;
} else {
textR.y = -(textR.height + gap);
}
} else if (verticalTextPosition == SwingUtilities.CENTER) {
textR.y = (iconR.height / 2) - (textR.height / 2);
} else { // (verticalTextPosition == BOTTOM)
if (horizontalTextPosition != SwingUtilities.CENTER) {
textR.y = iconR.height - textR.height;
} else {
textR.y = (iconR.height + gap);
}
}
if (horizontalTextPosition == SwingUtilities.LEFT) {
textR.x = -(textR.width + gap);
} else if (horizontalTextPosition == SwingUtilities.CENTER) {
textR.x = (iconR.width / 2) - (textR.width / 2);
} else { // (horizontalTextPosition == RIGHT)
textR.x = (iconR.width + gap);
}
// WARNING: DefaultTreeCellEditor uses a shortened version of
// this algorithm to position it's Icon. If you change how this
// is calculated, be sure and update DefaultTreeCellEditor too.
/* labelR is the rectangle that contains iconR and textR.
* Move it to its proper position given the labelAlignment
* properties.
*
* To avoid actually allocating a Rectangle, Rectangle.union
* has been inlined below.
*/
int labelR_x = Math.min(iconR.x, textR.x);
int labelR_width = Math.max(iconR.x + iconR.width,
textR.x + textR.width) - labelR_x;
int labelR_y = Math.min(iconR.y, textR.y);
int labelR_height = Math.max(iconR.y + iconR.height,
textR.y + textR.height) - labelR_y;
int dx, dy;
if (verticalAlignment == SwingUtilities.TOP) {
dy = viewR.y - labelR_y;
} else if (verticalAlignment == SwingUtilities.CENTER) {
dy = (viewR.y + (viewR.height / 2)) - (labelR_y + (labelR_height / 2));
} else { // (verticalAlignment == BOTTOM)
dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
}
if (horizontalAlignment == SwingUtilities.LEFT) {
dx = viewR.x - labelR_x;
} else if (horizontalAlignment == SwingUtilities.RIGHT) {
dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
} else { // (horizontalAlignment == CENTER)
dx = (viewR.x + (viewR.width / 2))
- (labelR_x + (labelR_width / 2));
}
/* Translate textR and glypyR by dx,dy.
*/
textR.x += dx;
textR.y += dy;
iconR.x += dx;
iconR.y += dy;
if (lsb < 0) {
// lsb is negative. Shift the x location so that the text is
// visually drawn at the right location.
textR.x -= lsb;
textR.width += lsb;
}
if (rsb > 0) {
textR.width -= rsb;
}
return text;
}
}
}
changing the border offset might help:
int OFFSET_TOP=50,OFFSET_BOTTOM=50;
label.setBorder(new TitledBorder(TITLE){
#Override
public Insets getBorderInsets(Component c, Insets insets){
return new Insets(insets.top - OFFSET_TOP, insets.left, insets.bottom - OFFSET_BOTTOM, insets.right);
}
});
i'm working with image processing, and i have a question.
I want read an image from project, and convert the image to gray.
I'm currently trying to do conversion with the function rgb2gray, but still not working.
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class ImageTesting extends Component {
private static int[] pixel;
private static BufferedImage b;
BufferedImage image;
public void paint(Graphics g) {
g.drawImage(image, 0, 0, null);
}
public ImageTesting() {
try {
image = ImageIO.read(new File("teste.jpg"));
} catch (IOException e) {
}
}
public Dimension getPreferredSize() {
if (image == null) {
return new Dimension(400, 400);
} else {
return new Dimension(image.getWidth(null), image.getHeight(null));
}
}
public static BufferedImage rgb2gray(BufferedImage bi) {
int heightLimit = bi.getHeight();
int widthLimit = bi.getTileWidth();
BufferedImage converted = new BufferedImage(widthLimit, heightLimit, BufferedImage.TYPE_BYTE_GRAY);
for (int height = 0; height < heightLimit; height++) {
for (int width = 0; width < widthLimit; width++) {
Color c = new Color(bi.getRGB(width, height) & 0x00fffff);
int newRed = (int) ((0.2989f * c.getRed()) * 2);// 0.2989f//multiplicr po 2
int newGreen = (int) ((0.5870f * c.getGreen()) * 2);// 0.5870f
int newBlue = (int) ((0.1140f * c.getBlue()) * 2);
int roOffset = newRed + newGreen + newBlue;
converted.setRGB(width, height, roOffset);
}
}
return converted;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
// TODO code application logic here
JFrame f = new JFrame("Load Image Sample");
JFrame g = new JFrame("Image RGB");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
g.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.add(new ImageTesting());
f.pack();
f.setVisible(true);
g.add(new ImageTesting());
rgb2gray(b);
}
}
When I run the program,these are the errors that appear.
If anyone could help me, i apreciate.
Thanks
Edit:
I managed to solve this problem,but now another question came up. To continue my work, i want to find the most 10 brilhants points in the resultant image, and return another image with black color in the index's that have the value 0, and white color in the index's that have value 1,but at this point i don't understand the best way to work out the steps.
It seems like there's something wrong with the main() method, isn't it? You create two completely identical JFrame instances, then add Imagetesting components that display the original image. And when running rgb2gray at the end, the result is sent nowhere.
I suggest using image filters, see related documentation here: http://www.jhlabs.com/ip/filters/
It's performant and simple to use.
I am trying to get a button with round edges. My button has a background color of yellow. I am not able to get the round edge for my button. Here is the code i am trying
class RoundedBorder implements Border {
int radius;
RoundedBorder(int radius) {
this.radius = radius;
}
public Insets getBorderInsets(Component c) {
return new Insets(this.radius+1, this.radius+1, this.radius+2, this.radius);
}
public boolean isBorderOpaque() {
return true;
}
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
g.drawRoundRect(x,y,width-1,height-1,radius,radius);
}
}
jButton1.setText(aContinue);
jButton1.setBackground(new java.awt.Color(255, 255, 0));
jButton1.setBorder(new RoundedBorder(20));
I am not able to get round edges using this piece of code.. Here is how my button looks .
I want to have round edges with no overflowing background color.
Option1- Use Images
Option2- Use the following code (Extracted from Make a button round)
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class RoundButton extends JButton {
public RoundButton(String label) {
super(label);
// These statements enlarge the button so that it
// becomes a circle rather than an oval.
Dimension size = getPreferredSize();
size.width = size.height = Math.max(size.width,
size.height);
setPreferredSize(size);
// This call causes the JButton not to paint
// the background.
// This allows us to paint a round background.
setContentAreaFilled(false);
}
// Paint the round background and label.
protected void paintComponent(Graphics g) {
if (getModel().isArmed()) {
// You might want to make the highlight color
// a property of the RoundButton class.
g.setColor(Color.lightGray);
} else {
g.setColor(getBackground());
}
g.fillOval(0, 0, getSize().width-1,
getSize().height-1);
// This call will paint the label and the
// focus rectangle.
super.paintComponent(g);
}
// Paint the border of the button using a simple stroke.
protected void paintBorder(Graphics g) {
g.setColor(getForeground());
g.drawOval(0, 0, getSize().width-1,
getSize().height-1);
}
// Hit detection.
Shape shape;
public boolean contains(int x, int y) {
// If the button has changed size,
// make a new shape object.
if (shape == null ||
!shape.getBounds().equals(getBounds())) {
shape = new Ellipse2D.Float(0, 0,
getWidth(), getHeight());
}
return shape.contains(x, y);
}
// Test routine.
public static void main(String[] args) {
// Create a button with the label "Jackpot".
JButton button = new RoundButton("Jackpot");
button.setBackground(Color.green);
// Create a frame in which to show the button.
JFrame frame = new JFrame();
frame.getContentPane().setBackground(Color.yellow);
frame.getContentPane().add(button);
frame.getContentPane().setLayout(new FlowLayout());
frame.setSize(150, 150);
frame.setVisible(true);
}
}
Option3- Use Look and Feel that supports Round Buttons http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/NimbusLookandFeel_OBE2012/CustomizingLandF.html
Option4- Go with JavaFX and use CSS. There are free CSS scripts supporting this
Found this great example by oracle which supplies a class which creates RoundButton.
Here is an example using an edited RoundButton class to create RoundedButton class:
import java.awt.AWTEvent;
import java.awt.AWTEventMulticaster;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
initComponents();
}
private void initComponents() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTextField tf = new JTextField("");
RoundedButton rb = new RoundedButton("Go");
rb.setBackground(Color.yellow);
rb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
JOptionPane.showMessageDialog(frame, "You said: " + tf.getText());
}
});
frame.add(tf, BorderLayout.NORTH);
frame.add(rb);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
class RoundedButton extends Component {
ActionListener actionListener; // Post action events to listeners
String label; // The Button's text
protected boolean pressed = false; // true if the button is detented.
/**
* Constructs a RoundedButton with no label.
*/
public RoundedButton() {
this("");
}
/**
* Constructs a RoundedButton with the specified label.
*
* #param label the label of the button
*/
public RoundedButton(String label) {
this.label = label;
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
/**
* gets the label
*
* #see setLabel
*/
public String getLabel() {
return label;
}
/**
* sets the label
*
* #see getLabel
*/
public void setLabel(String label) {
this.label = label;
invalidate();
repaint();
}
/**
* paints the RoundedButton
*/
#Override
public void paint(Graphics g) {
// paint the interior of the button
if (pressed) {
g.setColor(getBackground().darker().darker());
} else {
g.setColor(getBackground());
}
g.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 20, 20);
// draw the perimeter of the button
g.setColor(getBackground().darker().darker().darker());
g.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 20, 20);
// draw the label centered in the button
Font f = getFont();
if (f != null) {
FontMetrics fm = getFontMetrics(getFont());
g.setColor(getForeground());
g.drawString(label, getWidth() / 2 - fm.stringWidth(label) / 2, getHeight() / 2 + fm.getMaxDescent());
}
}
/**
* The preferred size of the button.
*/
#Override
public Dimension getPreferredSize() {
Font f = getFont();
if (f != null) {
FontMetrics fm = getFontMetrics(getFont());
int max = Math.max(fm.stringWidth(label) + 40, fm.getHeight() + 40);
return new Dimension(max, max);
} else {
return new Dimension(100, 100);
}
}
/**
* The minimum size of the button.
*/
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
/**
* Adds the specified action listener to receive action events from this
* button.
*
* #param listener the action listener
*/
public void addActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.add(actionListener, listener);
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
/**
* Removes the specified action listener so it no longer receives action
* events from this button.
*
* #param listener the action listener
*/
public void removeActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.remove(actionListener, listener);
}
/**
* Determine if click was inside round button.
*/
#Override
public boolean contains(int x, int y) {
int mx = getSize().width / 2;
int my = getSize().height / 2;
return (((mx - x) * (mx - x) + (my - y) * (my - y)) <= mx * mx);
}
/**
* Paints the button and distribute an action event to all listeners.
*/
#Override
public void processMouseEvent(MouseEvent e) {
Graphics g;
switch (e.getID()) {
case MouseEvent.MOUSE_PRESSED:
// render myself inverted....
pressed = true;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the Gauge example).
repaint();
break;
case MouseEvent.MOUSE_RELEASED:
if (actionListener != null) {
actionListener.actionPerformed(new ActionEvent(
this, ActionEvent.ACTION_PERFORMED, label));
}
// render myself normal again
if (pressed == true) {
pressed = false;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the Gauge example).
repaint();
}
break;
case MouseEvent.MOUSE_ENTERED:
break;
case MouseEvent.MOUSE_EXITED:
if (pressed == true) {
// Cancel! Don't send action event.
pressed = false;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the Gauge example).
repaint();
// Note: for a more complete button implementation,
// you wouldn't want to cancel at this point, but
// rather detect when the mouse re-entered, and
// re-highlight the button. There are a few state
// issues that that you need to handle, which we leave
// this an an excercise for the reader (I always
// wanted to say that!)
}
break;
}
super.processMouseEvent(e);
}
}
Another clean way to make this happen is to define a custom ButtonUI that would draw a rounded corner button.
I need a scroll pane with scrollbars only visible during scroll events or when needed to pull.
Something that looks like the scroll bars on the nowadays smartphones.
I searched a lot but found only realizations in javascript.
So I tried it by myself.
Has anyone a better solution or hints?
The animation classes can be found here: TimingFrameWork
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.plaf.ScrollBarUI;
import javax.swing.plaf.basic.BasicScrollBarUI;
import org.jdesktop.animation.timing.Animator;
import org.jdesktop.animation.timing.interpolation.KeyFrames;
import org.jdesktop.animation.timing.interpolation.KeyTimes;
import org.jdesktop.animation.timing.interpolation.KeyValues;
import org.jdesktop.animation.timing.interpolation.PropertySetter;
/**
* A scrollpane like component, where the scroll bars are floating over the
* scrollable view to indicate the current scroll positions.
* The scroll indicators appear smoothly during scroll events and disappear
* smoothly afterwards.
* <p>
* The scrollbars can be dragged just as normal.</p>
* <p>
* The usage is similar to a classic scrollpane.</p>
*
* #author Jolly Littlebottom
*/
public class JScrollIndicator extends JLayeredPane {
private static final Color THUMB_COLOR = Color.DARK_GRAY;
private static final Color THUMB_BORDER_COLOR = Color.LIGHT_GRAY;
private static final float MAX_ALPHA = 0.8f;
private static final int THUMB_THICKNESS = 7;
private static final int THUMB_MIN_SIZE = 48;
private static final int THUMB_MARGIN = 3;
private static final int FADE_IN_TIME = 300;
private static final int STAY_TIME = 2000;
private static final int FADE_OUT_TIME = 1000;
private final JScrollPane scrollPane;
private final ControlPanel controlPanel;
/**
* Creates a <code>JScrollIndicator</code> that displays the contents of the
* specified component, where both horizontal and vertical scrollbars appear
* whenever the component's contents are larger than the view and scrolling
* in underway or the mouse is over the scrollbar position.
*
* #see #setViewportView
* #param view the component to display in the scrollpane's viewport
*/
public JScrollIndicator(final JComponent view) {
this(view, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
}
/**
* Creates a <code>JScrollIndicator</code> that displays the view component
* in a viewport whose view position can be controlled with a pair of
* scrollbars.
* The scrollbar policies specify when the scrollbars are displayed,
* For example, if <code>vsbPolicy</code> is
* <code>JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED</code>
* then the vertical scrollbar only appears if the view doesn't fit
* vertically. The available policy settings are listed at
* {#link #JScrollPane.setVerticalScrollBarPolicy} and
* {#link #JScrollPane.setHorizontalScrollBarPolicy}.
*
* #param view the component to display in the scrollpanes viewport
* #param vsbPolicy an integer that specifies the vertical scrollbar policy
* #param hsbPolicy an integer that specifies the horizontal scrollbar policy
*/
public JScrollIndicator(final JComponent view, int vsbPolicy, int hsbPolicy) {
scrollPane = new JScrollPane(view, vsbPolicy, hsbPolicy);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
add(scrollPane, JLayeredPane.DEFAULT_LAYER);
controlPanel = new ControlPanel(scrollPane);
add(controlPanel, JLayeredPane.PALETTE_LAYER);
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
// listen to changes of JLayeredPane size
scrollPane.setSize(getSize());
scrollPane.getViewport().revalidate();
controlPanel.setSize(getSize());
controlPanel.revalidate();
}
});
}
/**
* Returns the scroll pane used by this scroll indicator.
* Use carefully (e.g. to set unit increments) because not all changes have an
* effect. You have to write listeners in this cases (e.g. for changing the
* scrollbar policy)
*
* #return
*/
public JScrollPane getScrollPane() {
return scrollPane;
}
private class ControlPanel extends JPanel {
private final JMyScrollBar vScrollBar;
private final JMyScrollBar hScrollBar;
private ControlPanel(JScrollPane scrollPane) {
setLayout(new BorderLayout());
setOpaque(false);
vScrollBar = new JMyScrollBar(JScrollBar.VERTICAL);
scrollPane.setVerticalScrollBar(vScrollBar);
scrollPane.remove(vScrollBar);
if (scrollPane.getVerticalScrollBarPolicy() != JScrollPane.VERTICAL_SCROLLBAR_NEVER) {
add(vScrollBar, BorderLayout.EAST);
}
hScrollBar = new JMyScrollBar(JScrollBar.HORIZONTAL);
scrollPane.setHorizontalScrollBar(hScrollBar);
scrollPane.remove(hScrollBar);
if (scrollPane.getHorizontalScrollBarPolicy() != JScrollPane.HORIZONTAL_SCROLLBAR_NEVER) {
add(hScrollBar, BorderLayout.SOUTH);
}
}
}
private class JMyScrollBar extends JScrollBar {
protected final MyScrollBarUI scrollUI;
public JMyScrollBar(int direction) {
super(direction);
scrollUI = new MyScrollBarUI(this);
super.setUI(scrollUI);
int size = THUMB_THICKNESS + THUMB_MARGIN;
setPreferredSize(new Dimension(size, size));
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
scrollUI.setVisible(true, true);
}
#Override
public void mouseExited(MouseEvent e) {
scrollUI.setVisible(false, false);
}
});
addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
scrollUI.setVisible(true, false);
}
});
}
#Override
public void setUI(ScrollBarUI ui) {
}
#Override
public void updateUI() {
}
#Override
public void paint(Graphics g) {
scrollUI.paintThumb(g, this); // just the thumb
}
#Override
public void repaint(Rectangle r) {
JScrollIndicator scrollIndicator = JScrollIndicator.this;
Rectangle rect = SwingUtilities.convertRectangle(this, r, scrollIndicator);
rect.grow(1, 1);
// ensure for a translucent thumb, that the view is first painted
scrollIndicator.repaint(rect);
}
}
public class MyScrollBarUI extends BasicScrollBarUI {
private JMyScrollBar scrollBar;
private float alpha = 0.0f;
private FadeAnimation fadeAnimation;
private MyScrollBarUI(JMyScrollBar scrollBar) {
this.scrollBar = scrollBar;
fadeAnimation = new FadeAnimation(this);
}
#Override
protected void installComponents() {
incrButton = new JButton();
decrButton = new JButton();
if (scrollBar.getOrientation() == JScrollBar.HORIZONTAL) {
int size = THUMB_THICKNESS + THUMB_MARGIN; // let lower right corner empty
incrButton.setPreferredSize(new Dimension(size, size));
}
else {
incrButton.setPreferredSize(new Dimension(THUMB_MARGIN, THUMB_MARGIN));
}
decrButton.setPreferredSize(new Dimension(THUMB_MARGIN, THUMB_MARGIN));
}
#Override
protected void installDefaults() {
super.installDefaults();
// ensure the minimum size of the thumb
int w = minimumThumbSize.width;
int h = minimumThumbSize.height;
if (scrollBar.getOrientation() == JScrollBar.VERTICAL) {
h = Math.max(h, Math.min(maximumThumbSize.height, THUMB_MIN_SIZE));
}
else {
w = Math.max(w, Math.min(maximumThumbSize.width, THUMB_MIN_SIZE));
}
minimumThumbSize = new Dimension(w, h);
}
private void paintThumb(Graphics g, JComponent c) {
if (alpha == 0.0f) {
return; // don't paint anything
}
g.setColor(getAlphaColor(THUMB_COLOR));
int radius = THUMB_THICKNESS >>> 1; // half width
Rectangle thumbBounds = getThumbBounds();
int x = thumbBounds.x;
int y = thumbBounds.y;
int w = thumbBounds.width;
int h = thumbBounds.height;
if (scrollBar.getOrientation() == JScrollBar.VERTICAL) {
w -= THUMB_MARGIN;
}
else {
h -= THUMB_MARGIN;
}
g.fillRoundRect(x, y, w, h, radius, radius);
g.setColor(getAlphaColor(THUMB_BORDER_COLOR));
g.drawRoundRect(x, y, w, h, radius, radius);
}
private Color getAlphaColor(Color color) {
if (alpha == 1.0f) {
return color;
}
int rgb = color.getRGB() & 0xFFFFFF; // color without alpha values
rgb |= ((int)(alpha*255)) << 24; // add alpha value
return new Color(rgb, true);
}
public void setAlpha(float alpha) {
this.alpha = alpha;
scrollBar.repaint(getThumbBounds());
}
public void setVisible(boolean visible, boolean mouseOver) {
if (visible) {
fadeAnimation.fadeIn(mouseOver);
}
else {
fadeAnimation.fadeOut();
}
scrollBar.repaint(getThumbBounds());
}
}
private class FadeAnimation {
private final MyScrollBarUI scrollUI;
private Animator fadeAnimator;
private Timer fadeOutTimer;
private boolean isFadeIn;
private FadeAnimation(MyScrollBarUI scrollUI) {
this.scrollUI = scrollUI;
}
public synchronized void fadeIn(boolean mouseOver) {
if (mouseOver) {
cancelTimer();
}
if (!isFadeIn) {
isFadeIn = true;
cancelAnimationAndTimer();
fadeAnimator = PropertySetter.createAnimator(
FADE_IN_TIME, scrollUI, "alpha",
new KeyFrames(KeyValues.create(scrollUI.alpha, MAX_ALPHA),
new KeyTimes(0.0f, 1.0f)));
fadeAnimator.start();
if (!mouseOver) {
fadeOutTimer = new Timer(FADE_IN_TIME + STAY_TIME,
new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
FadeAnimation.this.fadeOut();
}
});
fadeOutTimer.start();
}
}
}
public synchronized void fadeOut() {
cancelAnimationAndTimer();
if (isFadeIn) {
isFadeIn = false;
fadeAnimator = PropertySetter.createAnimator(
FADE_OUT_TIME, scrollUI, "alpha",
new KeyFrames(KeyValues.create(scrollUI.alpha, 0.0f),
new KeyTimes(0.0f, 1.0f)));
fadeAnimator.start();
}
}
private void cancelAnimationAndTimer() {
if (fadeAnimator != null && fadeAnimator.isRunning()) {
fadeAnimator.cancel();
fadeAnimator = null;
}
cancelTimer();
}
private void cancelTimer() {
if (fadeOutTimer != null) {
fadeOutTimer.stop();
fadeOutTimer = null;
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String text = "";
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
text += i + " - " + j;
}
text += "\n";
}
JTextArea area = new JTextArea(text);
JScrollIndicator scrollIndicator = new JScrollIndicator(area);
frame.getContentPane().add(scrollIndicator);
frame.setBounds(100, 100, 200, 300);
frame.setVisible(true);
}
});
}
}