i am not a native english speaker so, firstly sorry for the grammar.
I want to do an app that capture a selected area of a screen and save it. I did a few research and i did the code down below.
My questions are:
1 - How can i open a pdf file in this app ? (i tried use a method but it didnt work. I dont know exactly where to put it on the code)
2 - How can i save the selected area in a new file ? (a image file : JPEG, JPG,png)
3 - [the complex part] right now, the code only "save" one selected area each time. I want to capture a lot of parts of screen and save this in the same image file. one beside the other. How can i do this ?
Java Code:
package javaapplication39;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
public class ScreenCaptureRectangle {
Rectangle captureRect;
ScreenCaptureRectangle(final BufferedImage screen) {
final BufferedImage screenCopy = new BufferedImage(
screen.getWidth(),
screen.getHeight(),
screen.getType());
final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
JScrollPane screenScroll = new JScrollPane(screenLabel);
screenScroll.setPreferredSize(new Dimension(
(int)(screen.getWidth()/3),
(int)(screen.getHeight()/3)));
JPanel panel = new JPanel(new BorderLayout());
panel.add(screenScroll, BorderLayout.CENTER);
final JLabel selectionLabel = new JLabel(
"Drag a rectangle in the screen shot!");
panel.add(selectionLabel, BorderLayout.SOUTH);
repaint(screen, screenCopy);
screenLabel.repaint();
screenLabel.addMouseMotionListener(new MouseMotionAdapter() {
Point start = new Point();
#Override
public void mouseMoved(MouseEvent me) {
start = me.getPoint();
repaint(screen, screenCopy);
selectionLabel.setText("Start Point: " + start);
screenLabel.repaint();
}
#Override
public void mouseDragged(MouseEvent me) {
Point end = me.getPoint();
captureRect = new Rectangle(start,
new Dimension(end.x-start.x, end.y-start.y));
repaint(screen, screenCopy);
screenLabel.repaint();
selectionLabel.setText("Rectangle: " + captureRect);
}
});
JOptionPane.showMessageDialog(null, panel);
System.out.println("Rectangle of interest: " + captureRect);
}
public void repaint(BufferedImage orig, BufferedImage copy) {
Graphics2D g = copy.createGraphics();
g.drawImage(orig,0,0, null);
if (captureRect!=null) {
g.setColor(Color.RED);
g.draw(captureRect);
g.setColor(new Color(255,255,255,150));
g.fill(captureRect);
}
g.dispose();
}
public static void main(String[] args) throws Exception {
Robot robot = new Robot();
final Dimension screenSize = Toolkit.getDefaultToolkit().
getScreenSize();
final BufferedImage screen = robot.createScreenCapture(
new Rectangle(screenSize));
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ScreenCaptureRectangle(screen);
}
});
}
}
1 - How can i open a pdf file in this app ? (i tried use a method but it didnt work. I dont know exactly where to put it on the code)
Take a look at How to Integrate with the Desktop Class
2 - How can i save the selected area in a new file ? (a image file : JPEG, JPG,png)
Take a look at Writing/Saving an Image
3 - [the complex part] right now, the code only "save" one selected area each time. I want to capture a lot of parts of screen and save this in the same image file. one beside the other. How can i do this ?
Is, as you say, a much more complex question. You will have to modify the code so that instead of displaying the panel in a JOptionPane, it shows it within a JFrame, you then need to be able to either monitor the mouseReleaseEvent or provide some kind of action, may be a toolbar or menu option, that allows the user to save the selection.
Have a look at How to Use Menus, How to Use Buttons, Check Boxes, and Radio Buttons, How to Write an Action Listeners and How to Use Tool Bars for more details.
As a side note, the code will only allow you to capture a single screen, you might consider something like Drawing a bounding rectangle to select what area to record which will allow you to capture the entire virtual desktop (multiple screeens)
Related
When I try to use a GIF in a JLabel either resized or normal, it smears and produces an odd effect:
The GIF I'm using:
Layout of the JPanel it is attached to is null, and images that are accessed are part of a jar file.
Here's the code for creating and adding the label:
public JLabel j_Anim(String path, int width, int height, int xpos, int ypos, boolean applyscaling) throws Exception {
Image finimage;
if (!applyscaling) {
finimage = new ImageIcon(Main.class.getResource(path)).getImage();
} else {
finimage = (new ImageIcon(Main.class.getResource(path)).getImage()).getScaledInstance(width, height, Image.SCALE_DEFAULT);
}
JLabel im = new JLabel(new ImageIcon(finimage));
group.panel.add(im);
im.setBounds(xpos, ypos, width, height);
return im;
}
I'm fairly new to java, so any help would be greatly appreciated!
EDIT:
Minimal Reproducable Example:
import javax.swing.*;
import java.awt.*;
class Main extends JFrame {
public static void main(String[] args) {
Main ma = new Main();
}
Main() {
JPanel p = new JPanel();
this.setSize(300, 300);
this.add(p);
JLabel im = new JLabel(new ImageIcon(this.getClass().getResource("img/walk.gif")));
p.add(im);
this.setVisible(true);
this.pack();
}
}
EDIT 2:
This behaviour is only happening with gifs that have transparent backgrounds, standard solid-background gifs work fine. However, the issue is still unresolved because I need to use a gif with a transparent background. Thanks for the help so far!
EDIT 3:
The issue was solved by changing the gif's disposal method to background. I used this cmd script with imagemagick to generate a custom gif with the specified disposal method from a spritesheet:
set WIDE=50
set HIGH=75
set XCOORD=0
set YCOORD=0
set FRAMES=8
convert spritesheet.png ^
-set option:distort:viewport %[fx:%FRAMES%*%WIDE%]x%HIGH% ^
-set option:slider %[fx:%YCOORD%*(w/%WIDE%)+%XCOORD%] ^
-crop %WIDE%x%HIGH% +append +repage ^
-distort affine "%[slider],0 0,0" ^
-crop %WIDE%x%HIGH% +repage ^
-set delay 10 -loop 0 -set dispose Background result.gif
pause
exit
I new here, and I'm a beginner about developing. My problem is that I have couple of JTextField controls inside a JPanel which is inside a JFrame too, and the text field doesn't show the text that I pass by a method, and I don't know why, because the source for that is really simple.
THE PROBLEM
I want to show the coordinates of the mouse of a canvas that I get in a pair of text fields. That canvas is inside a frame like a panel which contain the couple of text fields. I'm going to put here the source of a canvas which in a MouseMotionListener is refer.
public void addPosicionPuntero(){
addMouseMotionListener(new MouseMotionAdapter(){
#Override
public void mouseMoved(MouseEvent evento){
x1 = evento.getX();
y1 = evento.getY();
updateUI();
panelCoordenadas pC = new panelCoordenadas();
pC.mostrarCoordenadas(x1,y1);
System.out.println(x1 + " --- " + y1);
}
#Override
public void mouseDragged(MouseEvent evento){
mouseMoved(evento);
}
});
}
well, now in other class the panel which includes the text field.
public class panelCoordenadas extends javax.swing.JPanel{
JTextField txfX = new JTextField("X");
JTextField txfY = new JTextField("Y");
public panelCoordenadas() {
this.setSize(100, 100);
//this.setBounds(60,50,100,60);
this.setLocation(50, 50);
this.setBackground(Color.yellow);
JLabel coordX = new JLabel("coordX");
JLabel coordY = new JLabel("coordY");
add(coordX);
add(coordY);
txfX.setEditable(false);
txfY.setEditable(false);
txfX.setSize(40, 20);
txfY.setSize(40, 20);
add(txfX);
add(txfY);
}
public void mostrarCoordenadas(int x, int y){
txfX.setText(String.valueOf(x));
txfY.setText(String.valueOf(y));
System.out.println("mostrarCoordenadas = " + x + " --- " + y);
updateUI();
}
}
I put a System.out to know if its gets the data. The data shows by screen but not for the text field.
If anybody knows what's the problem I'd glad to tell me.
Class names should NOT start with a lower case character. Have you seen a class in the JDK that does? Learn by example.
So "panelCoordenadas" should be PanelCoordenadas.
updateUI();
That is not needed. That method is used internally by Swing when the LAF changes. There is no need for you to invoke it in application code.
JLabel coordX = new JLabel("coordX");
JLabel coordY = new JLabel("coordY");
add(coordX);
add(coordY);
In the constructor of your class you create components and add the components to the panel. That is good. So now your panel can display the components.
In your MouseListener you have:
panelCoordenadas pC = new panelCoordenadas();
pC.mostrarCoordenadas(x1,y1);
So you create a panel but do nothing with the panel. The panel is just sitting in memory. You don't add it to the frame. This approach is wrong.
Don't keep creating a new instance of your PanelCoordenadas class.
Instead in your main class where you create your other components, you create an instance of the PanelCoodenadas class and add it to the frame. If you want to update the text fields of that instance, then you need to pass that variable as a parameter to the class where you define your MouseListener.
Background: Making a game in Swing. It is simple turn base game. Not a whole lot going on. Because of this I didn't think I would need to implement a Game Tick. Rather, my thought was when a component got changed or needed to be updated just simply revalidate/repaint that component on the fly rather than repainting the whole screen.
I have a GameJPanel which currently has all the components on it. This JPanel is the one that contains the components that get revalidated/repainted etc.
I figured I could make JLayeredPane that holds GameJPanel and my OptionJPanel. Have a Button on GameJPanel that when pressed causes the OptionJPanel to show on top of it and having its JPanel 50% transparent (so it gives the affect it dims the GameJPanel).
However, once I did this what happened was that the GameJPanel started to replace OptionJPanel components (because of the events... etc; repainting of the components).
So currently I am at a loss on what to do. I'm thinking if I had some sort of game tick I wouldn't be having this issue, however, I am not 100% certain. I'm a little worried if I implemented a gametick that the events in game will cause the GameJPanel components to show through for half a second then get replaced. There are some events that cause components to repaint themselves without manually doing it (like quick example for JLabel setText();)
As an example of what I'm trying to go for.
I have tried with a CardLayout but I couldn't figure out how to have the OptionJPanel be on top of GameJPanel while seeing GameJPanel in the background (I tried setting background color, setOpaque(false)..., tried to limit Option JPanel size but I think the CardLayout stretches it (not 100% sure)) all I got was a gray background when doing so.
I would prefer not to go the CardLayout route because in the future I also plan on placing components on top of the GameJPanel (like someone clicks a button, have another panel on a different layer have a component slide in or out etc).
I use CardLayout a ton with my other components in GameJPanel to swap screens around, but haven't had the need to have the other components behind the one showing to show through.
Any ideas on how to go about this would be great or even example code that shows this.
As noted above, you would use a JDialog, a component that is easy to make (similar to making a JFrame) and easy to place. Simply place it "relative-to" the JFrame, e.g.,
myDialog.setLocationRelativeTo(myJFrame);
... and it will automatically center itself on the JFrame. The tricky part is dimming the underlying JFrame, and for this you would need to use a JGlassPane added to the JFrame's rootpane, one set with a background color that uses an alpha composite value. The tricky part with this is to draw the darker background without causing side effects, and to do this, please read Rob Camick's (StackOverflow user camickr) excellent tutorial on drawing in Swing with alpha composites which you can find here: Java Tips Weblog: Backgrounds with Transparency
An example of such a program is shown here:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class DialogEg {
// path to example image used as "game" background
private static final String IMG_PATH = "https://upload.wikimedia.org/"
+ "wikipedia/commons/7/76/Jump_%27n_Bump.png";
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
// get the "game" background image, or exit if fail
BufferedImage img = null;
try {
URL imgUrl = new URL(IMG_PATH);
img = ImageIO.read(imgUrl);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
// pass "game" image into main JPanel so that it will be drawn
DeMainPanel mainPanel = new DeMainPanel(img);
JFrame frame = new JFrame("Dialog Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel); // add main JPanel to JFrame
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
// main JPanel
#SuppressWarnings("serial")
class DeMainPanel extends JPanel {
private BufferedImage img; // background image
// JButton action that shows the JDialog and darkens the glasspane
private PauseAction pauseAction = new PauseAction("Pause");
public DeMainPanel(BufferedImage img) {
super();
this.img = img;
add(new JButton(pauseAction));
}
// draw the "game" background image within the JPanel if not null
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
// size this JPanel to match the image's size
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || img == null) {
return super.getPreferredSize();
}
int width = img.getWidth();
int height = img.getHeight();
return new Dimension(width, height);
}
}
// Action / ActionListener for JButton -- shows JDialog and darkens glasspane
#SuppressWarnings("serial")
class PauseAction extends AbstractAction {
private static final int ALPHA = 175; // how much see-thru. 0 to 255
private static final Color GP_BG = new Color(0, 0, 0, ALPHA);
private DeDialogPanel deDialogPanel = new DeDialogPanel(); // jpanel shown in JDialog
public PauseAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
// comp is our JButton
Component comp = (Component) e.getSource();
if (comp == null) {
return;
}
// create our glass pane
JPanel glassPane = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
// magic to make it dark without side-effects
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
// more magic below
glassPane.setOpaque(false);
glassPane.setBackground(GP_BG);
// get the rootpane container, here the JFrame, that holds the JButton
RootPaneContainer win = (RootPaneContainer) SwingUtilities.getWindowAncestor(comp);
win.setGlassPane(glassPane); // set the glass pane
glassPane.setVisible(true); // and show the glass pane
// create a *modal* JDialog
JDialog dialog = new JDialog((Window)win, "", ModalityType.APPLICATION_MODAL);
dialog.getContentPane().add(deDialogPanel); // add its JPanel to it
dialog.setUndecorated(true); // give it no borders (if desired)
dialog.pack(); // size it
dialog.setLocationRelativeTo((Window) win); // ** Center it over the JFrame **
dialog.setVisible(true); // display it, pausing the GUI below it
// at this point the dialog is no longer visible, so get rid of glass pane
glassPane.setVisible(false);
}
}
// JPanel shown in the modal JDialog above
#SuppressWarnings("serial")
class DeDialogPanel extends JPanel {
private static final Color BG = new Color(123, 63, 0);
public DeDialogPanel() {
JLabel pausedLabel = new JLabel("PAUSED");
pausedLabel.setForeground(Color.ORANGE);
JPanel pausedPanel = new JPanel();
pausedPanel.setOpaque(false);
pausedPanel.add(pausedLabel);
setBackground(BG);
int eb = 15;
setBorder(BorderFactory.createEmptyBorder(eb, eb, eb, eb));
setLayout(new GridLayout(0, 1, 10, 10));
add(pausedPanel);
add(new JButton(new FooAction("RESUME")));
add(new JButton(new FooAction("RESTART")));
add(new JButton(new FooAction("EXIT TO MAP")));
}
// simple action -- all it does is to make the dialog no longer visible
private class FooAction extends AbstractAction {
public FooAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
Component comp = (Component) e.getSource();
Window win = SwingUtilities.getWindowAncestor(comp);
win.dispose(); // here -- dispose of the JDialog
}
}
}
The GUI looks like this initially:
but then when the dialog shows and the glass pane is darkened, it looks like this:
So after about a month of working on my game I was drawn to this post once again. I implemented part of my game with what DontKnowMuchButGettingBetter's way and also implemented this by just adding the components to the GlassPane so to speak (Made a JPanel, set it to be GlassPane, did whatever on that Panel)...
The later implementation (GlassPane), isn't the best way to go about this because then you can't use the glass pane for other useful things.
I came back to my original idea to use a JLayeredPane. Having different Components on different levels and working off that. My issue before was that when components were getting repainted, the components in the backer layers were over painting the ones in the front layer.
Well I just came across a method called isOptimizedDrawingEnabled()... By making this method always return false for the JLayeredPane I was able to achieve what I wanted.
First, I am a Web Developer and a novice Java programmer.
My boss is asking me to make this button in an application:
My custom button class must extend JButton or BasicButtonUI so that it can be reused.
I did some research on Stack Overflow, but I did not understand the answers, especially with the time restraints from my boss.
You should create your own component for this.
Override the paintComponent method on a JPanel, and inside the paintComponent method draw (ie fill) a rounded rectangle2D in the color gray :
RoundRectangle2D roundedRectangle = new RoundRectangle2D.Float(x, y, w, h, 10, 10);
g.fill(roundedRectangle);
(The last two values determine the curvature. Play around until you get what you want)
Now move the x,y and reduce width and height so that when you draw the next rectangle, it sits inside the gray rectangle. Set the graphics color to blue then do something like this :
RoundRectangle2D roundedRectangle2 = new RoundRectangle2D.Float(x + 5, y + 5, w - 10, h - 10, 10, 10);
g.fill(roundedRectangle2);
You will also need to add text. Adding text requires an x and y position. The exact x and y position can be tricky to calculate, so you may need to use FontMetrics to get some more information about the rectanglar shape of the string. Fontmetrics has methods like stringWidth() and getHeight() which will help you determine what your x and y should be.
g.drawString("Click Me", x, y);
Finally you need to have a mouse motion listener on your panel. The listener needs to find when the mouse is over the button and then redraw the component.
Your rectangle can be cast to a shape object, and a calculation can be made as to whether the mouse is in the shape. Eg :
shape.contains(x,y)
If it contains, change the color, then call repaint() or updateUI() on the panel.
Note: your color object should be kept as a class level field in the class, so that it can be changed via the mouseover.
Hope this helps!
If you don't want to draw the images by yourself using the graphics API or you can't becaue the images come from a graphic designer, than you can use them as ImageIcon objects and use setRolloverIcon() and setIcon().
In this case I would do it this way
class ButtonRollover {
private String normalImagePath;
private String rolloverImagePath;
public ButtonRollover(String normalImagePath, String rolloverImagePath) {
this.normalImagePath = normalImagePath;
this.rolloverImagePath = rolloverImagePath;
}
public void apply(AbstractButton abstractButton) {
abstractButton.setBorderPainted(false);
abstractButton.setBackground(new Color(0, 0, 0, 0));
abstractButton.setRolloverIcon(createImageIcon(rolloverImagePath));
abstractButton.setIcon(createImageIcon(normalImagePath));
}
private ImageIcon createImageIcon(String path) {
java.net.URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
}
and than use it. E.g.
public class Main extends JFrame {
public static void main(String[] args) {
Main main = new Main();
main.setBackground(Color.WHITE);
main.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
main.setSize(640, 480);
Container contentPane = main.getContentPane();
ButtonRollover buttonRollover = new ButtonRollover("/bt_normal.png",
"/bt_hover.png");
JButton btn = new JButton();
buttonRollover.apply(btn);
contentPane.add(btn);
main.setVisible(true);
}
}
Just put the image files in the classpath.
There are ways to do it.
1) JButton has inbuilt API setIcon. You could set ImageIcon here.
2) You could add mouse listener (Mouse entered, Mouse exited) change the icons to the needed ones.
3) Make a button round - Refer for creating the curvy buttons.
public class Main extends JFrame {
public static void main(String[] args) {
Main main = new Main();
main.setBackground(Color.WHITE);
main.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
main.setSize(640, 480);
Container contentPane = main.getContentPane();
ButtonRollover buttonRollover = new ButtonRollover("/bt_normal.png",
"/bt_hover.png");
JButton btn = new JButton();
buttonRollover.apply(btn);
contentPane.add(btn);
main.setVisible(true);
}
}
I'm a college student and this is my first time I have ever created a gui in Java. Right now I looked at this answer GUI in Java using Swing and followed the instructions and still nothing happens. Here is the code. I cut out all the irrelevant junk.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Lab4Shell
{
// this holds the current game board
private char[][] gameBoard = new char[7][8];
private JButton[][] gameButtons = new JButton[7][8];
private ImageIcon red = new ImageIcon("Red.jpg");
private ImageIcon black = new ImageIcon("Black.jpg");
private ImageIcon empty = new ImageIcon("Empty.jpg");
private JPanel panel = new JPanel();
private int currentPlayer = 1;
private int numMoves = 0;
//Why do you want everything in constructor?
public Lab4Shell()
{
CreateWindow();
ResetGame();
// set layout
// loop through buttons array creating buttons, registering event handlers and adding buttons to panel
// add panel to frame
// do other initialization of applet
}
public static void CreateWindow()
{
//Sets window title and create window object.
JFrame aWindow = new JFrame("Connect Four");
//Set window position and size
aWindow.setBounds(500,100,400,400);
//What close button does.
aWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Make window visible.
aWindow.setVisible(true);
}
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Lab4Shell game = new Lab4Shell();
}
});
}
void ResetGame()
{
JLabel label = new JLabel();
label.setIcon(empty);
for(int r=0;r<gameBoard.length;r++)
{
java.util.Arrays.fill(gameBoard[r],0,gameBoard[r].length,'0');
//loop through board columns
for(int c=0;c<gameBoard[r].length;c++)
{
}
}
// loop through array setting char array back to ' ' and buttons array back to empty pic
// reset currentPlayer and numMoves variables
}
You have to add the created ImageIcons to the panel as Manos said, and being the images at the src folder of Eclipse project, do that:
java.net.URL url = getClass().getResource("red.JPEG");
ImageIcon red = new ImageIcon(url);
If the resources are embedded with the application (within in the jar), the you need to use Class#getResource to load them.
The preferred mechanism for loading images is through the ImageIO API. It supports more image formats (as well as providing a pluggable architecture) and guarantees an image that is ready to be displayed once the read method returns
BufferedImage redImage;
// ...
URL url = getClass().getResource("red.JPEG");
if (url != null) {
redImage = ImageIO.read(url);
} else {
throw new NullPointerException("Unable to locate red image resource");
}
You can try this
BufferedImage myPicture = ImageIO.read(new File("path-to-file"));
JLabel picLabel = new JLabel(new ImageIcon( myPicture ));
add( picLabel );
You've never adding anything to your frame - which is causing your problem. So in you createWindow method, you need to call:
aWindow.setContentPane(panel);
Then later on (like in your resetGame method), you'll add your content (like the JLabel) to the panel:
panel.add(empty);
Where it's added to your panel is determined by the LayoutManager of the panel (there are many of them - the default is BorderLayout)
Other helpful things:
Generally, when it makes sense, create/initialize your objects in the constructor and add/remove/update them in the runtime.
For troubleshooting, use the .setOpaque(true) and .setBackground(Color.blue) methods on what you want to see. If you don't see it then, either something is covering it up, or it was never added
Good luck.