My Task:
Create an application that displays a Hangman graphic for 10 steps. This graphic should be controllable via a text field and a slider (in the range 0-10) for test purposes. The text box updates the graph as soon as the value is changed and does not wait until the Enter key is pressed. If an invalid value is entered in the text field, then an error message is displayed instead of the graphic (with the method drawString text can also be "drawn"), if there should be no value there, then the graphic should remain empty.
In my program, the change of the graphics on the JSlider works fine, but the input via the text field causes no change and the check when entering an incorrect value, I tried, but then nothing is displayed. I do not understand what's wrong because the JTextField approach is the same as JSlider ...
I have put the source code of both classes down below.
First Class:
Imports, Package...
public class HangmanFrame extends JFrame{
public HangmanFrame(){
super("Hangman");
HangmanPanel panel = new HangmanPanel();
JPanel mainPanel = new JPanel();
this.add(mainPanel);
mainPanel.setLayout(new BorderLayout());
JTextField t = new JTextField();
t.getDocument().addDocumentListener(new DocumentListener(){
#Override
public void changedUpdate(DocumentEvent arg0) {
try{
Integer.parseInt(t.getText());
}
catch(NumberFormatException ex){
System.out.println(ex.getMessage());
}
panel.repaint();
}
#Override
public void insertUpdate(DocumentEvent arg0) {
try{
Integer.parseInt(t.getText());
}
catch(NumberFormatException ex){
System.out.println(ex.getMessage());
}
panel.repaint();
}
#Override
public void removeUpdate(DocumentEvent arg0) {
try{
Integer.parseInt(t.getText());
}
catch(NumberFormatException ex){
System.out.println(ex.getMessage());
}
panel.repaint();
}
});
JSlider s = new JSlider(JSlider.HORIZONTAL, 0, 10, 0);
s.addChangeListener(new ChangeListener(){
#Override
public void stateChanged(ChangeEvent arg0) {
panel.repaint();
}
});
panel.setSlider(s);
panel.setTextField(t);
mainPanel.add(panel, BorderLayout.CENTER);
mainPanel.add(s, BorderLayout.PAGE_END);
mainPanel.add(t, BorderLayout.PAGE_START);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setSize(300,500);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public static void main(String[] args) {
new HangmanFrame();
}
}
Second Class:
public class HangmanPanel extends JPanel {
private JSlider slider;
private JTextField field; //Height 500, Width 300
public void paintComponent(Graphics g){
super.paintComponent(g);
int sliderValue = slider.getValue();
String fieldValue = field.getText();
//int fieldInt = Integer.parseInt(fieldValue);
g.drawLine(0, super.getWidth() + 99, super.getHeight(), super.getWidth() + 99);
if(sliderValue == 0 || fieldValue.equals("0")){
return;
}
g.setColor(new Color(205,133,63));
int xArc = this.getWidth() / 20;
int yArc = this.getHeight() - this.getHeight() / 5;
int arcWidth = this.getWidth() / 2;
int arcHeight = this.getHeight() / 5;
g.fillArc(xArc, yArc, arcWidth, arcHeight, 0, 180);
if(sliderValue == 1 || fieldValue.equals("1")){
return;
}
g.setColor(Color.BLACK);
int x1Line = xArc + arcWidth / 2;
int x2Line = x1Line;
int y1Line = yArc;
int y2Line = this.getHeight() / 6;
g.drawLine(x1Line, y1Line, x2Line, y2Line);
if(sliderValue == 2 || fieldValue.equals("2")){
return;
}
int x3Line = x1Line;
int x4Line = x3Line + (this.getWidth() / 3) + 20;
int y3Line = y2Line;
int y4Line = y3Line;
g.drawLine(x3Line, y3Line, x4Line, y4Line);
if(sliderValue == 3 || fieldValue.equals("3")){
return;
}
int x5Line = x4Line;
int x6Line = x5Line;
int y5Line = y4Line;
int y6Line = y5Line + this.getWidth() / 5; // + 60
g.drawLine(x5Line, y5Line, x6Line, y6Line);
if(sliderValue == 4 || fieldValue.equals("4")){
return;
}
g.setColor(new Color(255, 221, 204));
g.fillOval(x6Line - this.getHeight() / 20, y6Line, this.getHeight() / 10, this.getHeight() / 10); // -25, ...,50, 50
if(sliderValue == 5 || fieldValue.equals("5")){
return;
}
g.setColor(Color.BLUE);
g.fillOval((int) ((int) x6Line - this.getHeight() / 14.7) , (int) (y6Line + this.getHeight() / 10.41), (int)(this.getHeight() / 7.14), (int)(this.getHeight() / 4.16)); // 34, 48, 70, 120
if(sliderValue == 6 || fieldValue.equals("6")){
return;
}
int x7Line = x6Line + (int)(this.getHeight() / 17.85); // 28
int x8Line = x7Line + (int)(this.getHeight() / 12.5); // 40
int y7Line = y6Line + (int)(this.getHeight() / 7.14); // 70
int y8Line = y7Line - (int)(this.getHeight() / 14.28); // 35
g.setColor(Color.BLACK);
g.drawLine(x7Line, y7Line, x8Line, y8Line);
if(sliderValue == 7 || fieldValue.equals("7")){
return;
}
int x9Line = x7Line - (int)(this.getHeight() / 9.43); // 53
int x10Line = x9Line - (int)(this.getHeight() / 14.28); // 35
int y9Line = y7Line;
int y10Line = y8Line;
g.drawLine(x9Line, y9Line, x10Line, y10Line);
if(sliderValue == 8 || fieldValue.equals("8")){
return;
}
int x11Line = x7Line;
int x12Line = x8Line;
int y11Line = y7Line + (int)(this.getHeight() / 6.66); // 75
int y12Line = y8Line + (int)(this.getHeight() / 3.33); // 150
g.drawLine(x11Line, y11Line, x12Line, y12Line);
if(sliderValue == 9 || fieldValue.equals("9")){
return;
}
int x13Line = x9Line;
int x14Line = x10Line;
int y13Line = y11Line;
int y14Line = y12Line;
g.drawLine(x13Line, y13Line, x14Line, y14Line);
}
public void setSlider(JSlider slider){
this.slider = slider;
}
public void setTextField(JTextField field){
this.field = field;
}
}
Your JTextField reading works, but a problem is that you're first checking for the slider's value, and so if the slider if check is true, the method short circuits. To prove that it's working, move the slider all the way to the right, and then enter 1 or 2 into the JTextField.
If this were my project and I wanted to test this effect, I'd get all logic out of the painting method and instead allow my controllers to change a state value of the observed class, call repaint() and then draw the image based on that state.
For example, something like so:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
#SuppressWarnings("serial")
public class HangmanGUI2 extends JPanel {
private HangmanModel model = new HangmanModel();
private HangmanPanel2 panel2 = new HangmanPanel2(model);
private JSlider slider = new JSlider(0, HangmanModel.MAX_VALUE, 0);
private JTextField textField = new JTextField(10);
public HangmanGUI2() {
textField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void removeUpdate(DocumentEvent e) {
updateModel(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
updateModel(e);
}
#Override
public void changedUpdate(DocumentEvent e) {
updateModel(e);
}
private void updateModel(DocumentEvent e) {
Document doc = e.getDocument();
int length = doc.getLength();
try {
String text = doc.getText(0, length);
int value = Integer.parseInt(text.trim());
setModelValue(value);
} catch (BadLocationException e1) {
e1.printStackTrace();
} catch (NumberFormatException e1) {
// Do Nothing
}
}
});
slider.setMajorTickSpacing(1);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(e -> {
int value = slider.getValue();
setModelValue(value);
});
setLayout(new BorderLayout());
add(panel2);
add(textField, BorderLayout.PAGE_START);
add(slider, BorderLayout.PAGE_END);
// new Timer(1000, e -> {
// model.increment();
// repaint();
// }).start();
}
protected void setModelValue(int value) {
model.setValue(value);
repaint();
}
private static void createAndShowGui() {
HangmanGUI2 mainPanel = new HangmanGUI2();
JFrame frame = new JFrame("HangmanGUI2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class HangmanModel {
public static final int MAX_VALUE = 9;
private int value = 0;
public int getValue() {
return value;
}
public void increment() {
setValue(getValue() + 1);
}
public void setValue(int value) {
this.value = Math.min(value, MAX_VALUE);
this.value = Math.max(this.value, 0);
}
}
#SuppressWarnings("serial")
class HangmanPanel2 extends JPanel {
private HangmanModel model;
private List<Image> images = ImageCreator.getImages();
public HangmanPanel2(HangmanModel model) {
this.model = model;
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || images.size() == 0) {
return super.getPreferredSize();
}
int w = images.get(0).getWidth(this);
int h = images.get(0).getHeight(this);
return new Dimension(w, h);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(images.get(model.getValue()), 0, 0, this);
}
}
class ImageCreator {
private static final int W = 284;
private static final int H = 425;
private static final Color BASE_COLOR = new Color(205, 133, 63);
public static List<Image> getImages() {
List<Image> images = new ArrayList<>();
BufferedImage img = new BufferedImage(W, H, BufferedImage.TYPE_INT_ARGB);
images.add(createImageCopy(img));
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(BASE_COLOR);
int xArc = W / 20;
int yArc = H - H / 5;
int arcWidth = W / 2;
int arcHeight = H / 5;
g2.fillArc(xArc, yArc, arcWidth, arcHeight, 0, 180);
images.add(createImageCopy(img));
// -----------------------------------------
g2.setColor(Color.BLACK);
int x1Line = xArc + arcWidth / 2;
int x2Line = x1Line;
int y1Line = yArc;
int y2Line = H / 6;
g2.drawLine(x1Line, y1Line, x2Line, y2Line);
images.add(createImageCopy(img));
// -----------------------------------------
int x3Line = x1Line;
int x4Line = x3Line + (W / 3) + 20;
int y3Line = y2Line;
int y4Line = y3Line;
g2.drawLine(x3Line, y3Line, x4Line, y4Line);
images.add(createImageCopy(img));
// -----------------------------------------
int x5Line = x4Line;
int x6Line = x5Line;
int y5Line = y4Line;
int y6Line = y5Line + W / 5; // + 60
g2.drawLine(x5Line, y5Line, x6Line, y6Line);
// -----------------------------------------
g2.setColor(new Color(255, 221, 204));
g2.fillOval(x6Line - H / 20, y6Line, H / 10,
H / 10); // -25, ...,50, 50
images.add(createImageCopy(img));
// -----------------------------------------
g2.setColor(Color.BLUE);
g2.fillOval((int) ((int) x6Line - H / 14.7),
(int) (y6Line + H / 10.41), (int) (H / 7.14),
(int) (H / 4.16)); // 34, 48, 70, 120
images.add(createImageCopy(img));
// -----------------------------------------
int x7Line = x6Line + (int) (H / 17.85); // 28
int x8Line = x7Line + (int) (H / 12.5); // 40
int y7Line = y6Line + (int) (H / 7.14); // 70
int y8Line = y7Line - (int) (H / 14.28); // 35
g2.setColor(Color.BLACK);
g2.drawLine(x7Line, y7Line, x8Line, y8Line);
images.add(createImageCopy(img));
// -----------------------------------------
int x9Line = x7Line - (int) (H / 9.43); // 53
int x10Line = x9Line - (int) (H / 14.28); // 35
int y9Line = y7Line;
int y10Line = y8Line;
g2.drawLine(x9Line, y9Line, x10Line, y10Line);
images.add(createImageCopy(img));
// -----------------------------------------
int x11Line = x7Line;
int x12Line = x8Line;
int y11Line = y7Line + (int) (H / 6.66); // 75
int y12Line = y8Line + (int) (H / 3.33); // 150
g2.drawLine(x11Line, y11Line, x12Line, y12Line);
images.add(createImageCopy(img));
// -----------------------------------------
int x13Line = x9Line;
int x14Line = x10Line;
int y13Line = y11Line;
int y14Line = y12Line;
g2.drawLine(x13Line, y13Line, x14Line, y14Line);
images.add(createImageCopy(img));
g2.dispose();
return images;
}
private static Image createImageCopy(BufferedImage img) {
int w = img.getWidth();
int h = img.getHeight();
BufferedImage img2 = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics g = img2.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
return img2;
}
}
Related
I'm new to gui java and I've been trying to recreate the game called" jump it" (http://www.crazygames.com/game/jump-it) and I'm currently on the process of making the randomized rectangles for my character to jump on. However I ran my code and I had no errors, but the rectangles that I made isn't showing up. I attached my code underneath, it's kinda long sorry about that.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.Random;
import java.util.TimerTask;
class GuiGame{
public static void main(String args[]) {
JFrame f = new JFrame("RUN - Christine & Esther"); //title of frame
Container cont = f.getContentPane(); // get container - top of the frame
cont.setLayout(new BorderLayout());
BtnActPanel bp = new BtnActPanel(); // create an object of our game panel
cont.add(bp, BorderLayout.CENTER );
f.setVisible(true);
f.setSize(975,613); //size of frame
}
}
class Rectangle{
static Random r = new Random();
static int upperX = 100;
static int lowerX = 20;
static int upperY = 550;
static int lowerY = 450;
static int minWidth = 200;
static int maxWidth = 600;
static int minHeight = 40;
static int maxHeight = 140;
static int x = 0, y = 0, w = 0, h = 0, check = 0;
public Rectangle(){
check++;
int x = 650 + 50*check;
int y = r.nextInt(upperY-lowerY + 1) + lowerY; // from 450 to 550
int w = r.nextInt(maxWidth-minWidth + 1) + minWidth; // from 200 to 600
int h = r.nextInt(maxHeight - minHeight + 1) + minHeight; // from 40 to 140
}
public int getx(){
return x;
}
public int gety(){
return y;
}
public int getw(){
return w;
}
public int geth(){
return h;
}
}
class BtnActPanel extends JPanel implements ActionListener{
//variables
private JButton b1, b2, b3;
private JPanel background;
private JPanel game;
private Timer t, timer;
private int x = 0, check1 = 0, index = 0, x1 = 650, count2 = 0,
y2 = (int)(Math.random()*100)+40, y1 = (int)(Math.random()*100)+450,
x2 = (int)(Math.random()*600)+200, xaxis = 0, yaxis = 0, w = 0, h = 0, count = 0;
private ImageIcon []arrImage;
private boolean check2;
private static ImageIcon icon, exitButton, startButton, questionButton, b, instruct, c ;
public BtnActPanel(){
c = new ImageIcon("character.png"); // constructor
t = new Timer (100,this);
arrImage = new ImageIcon[2];
arrImage[0] = new ImageIcon("character.png");
arrImage[1] = new ImageIcon("character2.png");
startButton = new ImageIcon("startButton.png");//start button image
questionButton = new ImageIcon("QuestionButton.png"); //question button image
exitButton = new ImageIcon("exitButton.png"); //exit button image
icon = new ImageIcon("Title.jpg");//title image
b1 = new JButton(questionButton); // creates first button
//only shows button image with borders
b1.setOpaque(false);
b1.setContentAreaFilled(false);
b1.setBorderPainted(false);
b1.setFocusPainted(false);
b2 = new JButton(startButton);// creates second button
//only shows button image with borders
b2.setOpaque(false);
b2.setContentAreaFilled(false);
b2.setBorderPainted(false);
b2.setFocusPainted(false);
b3 = new JButton(exitButton);// creates third button
//only shows button image with borders
b3.setOpaque(false);
b3.setContentAreaFilled(false);
b3.setBorderPainted(false);
b3.setFocusPainted(false);
//adds buttons to code
this.add(b1);
this.add(b2);
this.add(b3);
b1.addActionListener(this);
b2.addActionListener(this);
b3.addActionListener(this);
}// end of constructor
public void actionPerformed(ActionEvent e) { //checks which button the user presses and performs actions based off choice
if(e.getSource() == b1){
check1 = 2;
this.remove(b1);
this.remove(b3);
repaint();
instruct = new ImageIcon("Instructions.jpg");
}
else if (e.getSource() == b2){
t.start();
check1 = 1;
this.remove(b1);
this.remove(b2);
this.remove(b3);
repaint();
b = new ImageIcon("toskyline.png");
}
else if (e.getSource() == b3){
JOptionPane.showMessageDialog(null, "This is an exit button, hope you enjoyed the game! :)", "Exit message",JOptionPane.WARNING_MESSAGE ); //shows exit message
System.exit(0);//exits program
}
else if (e.getSource() == t){
if (index == 0){
index = 1;
c = arrImage[1];
}
else{
index = 0;
c = arrImage[0];
}
if(count%50 == 0 && count >= 50){
Rectangle obstacle = new Rectangle();
int xaxis = obstacle.getx();
int yaxis = obstacle.gety();
int w = obstacle.getw();
int h = obstacle.geth();
xaxis = xaxis - 10;
count2 = 1;
}
x = x - 10;
x1 = x1 - 10;
repaint();
}
}
public void paintComponent(Graphics g){//this method draws and paints images and icons based on the user decisions
super.paintComponent(g);
if(check1 == 0)[enter image description here][1]
g.drawImage(icon.getImage(),0,0,null);
if(check1 == 1){
g.drawImage(b.getImage(),0,0,null);
g.setColor(Color.black);
g.fillRect(x,495, 500, 35);
g.fillRect(x1, y1, x2, y2);
count++;
System.out.println(count);
if(count2 == 1){
g.fillRect(xaxis, yaxis, w, h);
count2 = 0;
}
g.drawImage(c.getImage(), 100, 460, null);
}
if(check1 == 2)
g.drawImage(instruct.getImage(),0,0,null);
b1.setBounds(320, 350, 100, 100);
b2.setBounds(420, 350, 100, 100);
b3.setBounds(520, 350, 100, 100);
}
}//end of class
Using your ranges I made a demo.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Demo extends JPanel implements ActionListener {
final static int height = 800;
final static int width = 800;
final static String title = "title";
JFrame frame = new JFrame("default title");
Timer timer;
static Random r = new Random();
static int upperX = 100;
static int lowerX = 20;
static int upperY = 550;
static int lowerY = 450;
static int minWidth = 200;
static int maxWidth = 600;
static int minHeight = 40;
static int maxHeight = 140;
List<MyRectangle> rectangles = new ArrayList<>();
public static void main(String[] args) {
SwingUtilities
.invokeLater(() -> new Demo().start());
}
public Demo() {
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.setPreferredSize(
new Dimension(width, height));
setBackground(Color.WHITE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void start() {
timer = new Timer(0, this);
timer.setDelay(1000);
timer.start();
}
public void actionPerformed(ActionEvent ae) {
rectangles.add(createRectangle());
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (MyRectangle r : rectangles) {
g2d.setColor(Color.black);
g2d.drawRect(r.x, r.y, r.width, r.height);
g2d.setColor(r.color);
g2d.fillRect(r.x+1, r.y+1, r.width-1,r.height-1);
}
g2d.dispose();
}
Color[] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.ORANGE, Color.GRAY};
int color = 0;
public MyRectangle createRectangle() {
int y = r.nextInt(upperY - lowerY + 1) + lowerY; // from 450 to 550
int w = r.nextInt(maxWidth - minWidth + 1)
+ minWidth; // from 200 to 600
int h = r.nextInt(maxHeight - minHeight + 1)
+ minHeight; // from 40 to 140
int x = r.nextInt(upperX - lowerX + 1) + lowerX;
Color c = colors[color++ % colors.length];
return new MyRectangle(c, x, y, w, h);
}
class MyRectangle extends Rectangle {
Color color;
MyRectangle(Color c, int x, int y, int w, int h) {
super(x, y, w, h);
this.color = c;
}
}
}
This extends the JDK class Rectangle and adds a color field to the subclass. It displays a new rectangle very second.
When you click in a box, it should create a circle in that box from the designated coordinate. Unless if its already there then its removed. How do I get currentx and currenty coordinates into the fill oval?
public class Grid extends Applet{
boolean click;
public void init()
{
click = false;
addMouseListener(new MyMouseListener());
}
public void paint(Graphics g)
{
super.paint(g);
g.drawRect(100, 100, 400, 400);
//each box
g.drawRect(100, 100, 100, 100);
g.drawRect(200, 100, 100, 100);
g.drawRect(300, 100, 100, 100);
g.drawRect(400, 100, 100, 100);
//2y
g.drawRect(100, 200, 100, 100);
g.drawRect(200, 200, 100, 100);
g.drawRect(300, 200, 100, 100);
g.drawRect(400, 200, 100, 100);
//3y1x
g.drawRect(100, 300, 100, 100);
g.drawRect(200, 300, 100, 100);
g.drawRect(300, 300, 100, 100);
g.drawRect(400, 300, 100, 100);
//4y1x
g.drawRect(100, 400, 100, 100);
g.drawRect(200, 400, 100, 100);
g.drawRect(300, 400, 100, 100);
g.drawRect(400, 400, 100, 100);
if (click)
{
g.fillOval(currentx, currenty, 100, 100); // problem HERE
}
}
private class MyMouseListener implements MouseListener
{
public void mouseClicked(MouseEvent e)
{
int nowx = e.getX();
int nowy = e.getY();
nowx = nowx / 100;
String stringx = Integer.toString(nowx);
stringx = stringx+"00";
int currentx = Integer.parseInt(stringx);
nowy = nowy /100;
String stringy = Integer.toString(nowy);
stringy = stringy+"00";
int currenty = Integer.parseInt(stringy);
click = true;
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
}
Your main problem is, painting in Swing/AWT is destructive, that is, each time your paint method is called, you are expected to repaint the current state of the component.
In that case, what you really need is some way to model the state of the game so when paint is called, you can repaint it in some meaningful way. This a basic concept of a Model-View-Controller paradigm, where you separate the responsibility of the program into separate layers.
The problem then becomes, how do you translate from the view to model?
The basic idea is take the current x/y coordinates of the mouse and divide it by the cell size. You also need to ensure that the results are within the expected ranges, as you could get a result which is beyond the columns/rows of grids
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
protected static final int CELL_COUNT = 3;
private int[][] board;
private int[] cell;
private boolean isX = true;
public TestPane() {
board = new int[CELL_COUNT][CELL_COUNT];
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int[] cell = getCellAt(e.getPoint());
if (board[cell[0]][cell[1]] == 0) {
board[cell[0]][cell[1]] = isX ? 1 : 2;
isX = !isX;
repaint();
}
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
cell = getCellAt(e.getPoint());
repaint();
}
});
}
protected int[] getCellAt(Point p) {
Point offset = getOffset();
int cellSize = getCellSize();
int x = p.x - offset.x;
int y = p.y - offset.y;
int gridx = Math.min(Math.max(0, x / cellSize), CELL_COUNT - 1);
int gridy = Math.min(Math.max(0, y / cellSize), CELL_COUNT - 1);
return new int[]{gridx, gridy};
}
protected Point getOffset() {
int cellSize = getCellSize();
int x = (getWidth() - (cellSize * CELL_COUNT)) / 2;
int y = (getHeight() - (cellSize * CELL_COUNT)) / 2;
return new Point(x, y);
}
protected int getCellSize() {
return Math.min(getWidth() / CELL_COUNT, getHeight() / CELL_COUNT) - 10;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Point offset = getOffset();
int cellSize = getCellSize();
if (cell != null) {
g2d.setColor(new Color(0, 0, 255, 128));
g2d.fillRect(
offset.x + (cellSize * cell[0]),
offset.y + (cellSize * cell[1]),
cellSize,
cellSize);
}
g2d.setColor(Color.BLACK);
FontMetrics fm = g2d.getFontMetrics();
for (int col = 0; col < CELL_COUNT; col++) {
for (int row = 0; row < CELL_COUNT; row++) {
int value = board[col][row];
int x = offset.x + (cellSize * col);
int y = offset.y + (cellSize * row);
String text = "";
switch (value) {
case 1:
text = "X";
break;
case 2:
text = "O";
break;
}
x = x + ((cellSize - fm.stringWidth(text)) / 2);
y = y + ((cellSize - fm.getHeight()) / 2) + fm.getAscent();
g2d.drawString(text, x, y);
}
}
int x = offset.x;
int y = offset.y;
for (int col = 1; col < CELL_COUNT; col++) {
x = offset.x + (col * cellSize);
g2d.drawLine(x, y, x, y + (cellSize * CELL_COUNT));
}
x = offset.x;
for (int row = 1; row < CELL_COUNT; row++) {
y = offset.x + (row * cellSize);
g2d.drawLine(x, y, x + (cellSize * CELL_COUNT), y);
}
g2d.dispose();
}
}
}
First off, if you want to truncate a number to the nearest 100, e.g. 142 becomes 100, all you have to do is:
num = (num/100)*100;
this is because when you divide 2 integers it automatically truncates it, and you can just multiply it back to get the number. And what I think you want in this case is to create some field variables and some accessor methods. At the top of your MouseListener class, you will need to add:
private int mouseX=0;
private int mouseY=0;
then to be able to access these variables from outside of the mouselistener class you will need to add accessor methods:
public int getMouseX(){
return mouseX;
}
in your Grid Class, you can add the field:
private MyMouseListener listener;
and then initialize it in your init by doing:
listener = new MyMouseListener();
addMouseListener(listener);
then you can do the same for mouseY, and finally from your paint method you can then call:
int mouseX = listener.getMouseX();
int mouseY = listener.getMouseY();
and from there it is as simple as doing if statements or switch statements to find which box you clicked in!
Im wondering if anyone can help me replicate the below screenshot.
im tring to display a counter that will count in increments of 20 up to 100 the will count up 1 on the left hand side number then keep counting in increments and replicate..
eg:000 > 0/0/20 0/1/60
> 0/0/40 0/1/80
> 0/0/60 0/2/00
> 0/0/80 0/2/20
> 0/1/00 >>>>
> 0/1/20 0/9/80
> 0/1/40 1/0/00
etc...
This is an incredibly basic example. There is a lot of room for improvement in it's range checking.
The linear scroller is really simple. In the end I used the same basic concept as I did for the circular scroller, simply creating a BufferedImage with all the values marked on it, and based on the value, calculate the appropriate layout position.
The circular scroller took a little longer to bring about. The end result is really rather basic, the trouble is in calculating the under and overflow values.
The circular scroll simple creates a BufferedImage of all the available values. Based on it's display position, we either paint another copy of it before or after it, to give the illusion of flow...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.BoundedRangeModel;
import javax.swing.DefaultBoundedRangeModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class Altimiter {
public static void main(String[] args) {
new Altimiter();
}
public Altimiter() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private AltPane altPane;
public TestPane() {
JButton up = new JButton("+");
JButton down = new JButton("-");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
add(up, gbc);
gbc.gridy++;
add(down, gbc);
gbc.gridx++;
gbc.gridy = 0;
gbc.gridheight = GridBagConstraints.REMAINDER;
altPane = new AltPane();
add(altPane, gbc);
up.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
altPane.setSpeed(25);
}
});
down.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
altPane.setSpeed(-25);
}
});
altPane.setValue(0);
}
}
public class AltPane extends JPanel {
private LinearScrollerPane major;
private CircularScrollerPane minor;
private int altitude = 0;
private int direction = 0;
private Timer timer;
public AltPane() {
major = new LinearScrollerPane();
minor = new CircularScrollerPane();
major.setOpaque(false);
minor.setOpaque(false);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.VERTICAL;
gbc.weighty = 1;
add(major, gbc);
gbc.gridx++;
add(minor, gbc);
setBorder(new LineBorder(Color.BLUE));
timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
altitude += direction;
if (altitude < 0) {
((Timer) e.getSource()).stop();
altitude = 0;
} else if (altitude > 20000) {
((Timer) e.getSource()).stop();
altitude = 20000;
}
System.out.println("value = " + altitude);
setValue(altitude);
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.setInitialDelay(0);
}
public void setSpeed(int speed) {
this.direction = speed;
timer.start();
}
public void setValue(int value) {
int hnds = value / 100;
int units = value - (hnds * 100);
if (units == 0) {
if (hnds > 0 && direction > 0) {
units = 100;
} else if (hnds > 0 && direction < 0) {
units = -1;
} else {
units = 0;
}
}
major.setValue(hnds);
minor.setValue(units);
invalidate();
repaint();
}
public int getValue() {
int ths = major.getValue();
int hnds = minor.getValue();
return (ths * 100) + hnds;
}
#Override
public void paint(Graphics g) {
super.paint(g);
Insets insets = getInsets();
int width = getWidth() - (insets.left + insets.top);
int height = getHeight() - (insets.top + insets.bottom);
g.setColor(new Color(255, 0, 0, 128));
int centerY = insets.top + (height / 2);
g.drawLine(insets.left, centerY, insets.left + width, centerY);
}
}
public class CircularScrollerPane extends JPanel {
private BufferedImage baseView;
private BoundedRangeModel model;
private float startValue = 0;
private float currentValue = 0;
private float targetValue = 0;
private int rowCount = 3;
private Timer timer;
private long startTime;
private int runTime = 1000;
public CircularScrollerPane() {
setModel(new DefaultBoundedRangeModel(0, 20, 0, 100));
timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
long now = System.currentTimeMillis();
long diff = now - startTime;
if (diff >= runTime) {
((Timer) (e.getSource())).stop();
diff = runTime;
}
float progress = (float) diff / (float) runTime;
currentValue = calculateProgress(startValue, targetValue, progress);
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(false);
}
public int getValue() {
return getModel().getValue();
}
public void setValue(int value) {
timer.stop();
BoundedRangeModel model = getModel();
if (value < model.getMinimum()) {
value = model.getMaximum() + (value + 1);
currentValue += model.getMaximum(); // overflow
} else if (value > model.getMaximum() - model.getExtent()) {
value = model.getMinimum() + (value - model.getMaximum());
currentValue -= model.getMaximum(); // underflow
}
startValue = currentValue;
targetValue = value;
model.setValue(value);
startTime = System.currentTimeMillis();
timer.start();
}
#Override
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(getFont());
return fm == null ? super.getPreferredSize() : new Dimension(fm.stringWidth("MMM"), fm.getHeight() * getRowCount());
}
public void setRowCount(int value) {
if (value != rowCount) {
int old = rowCount;
rowCount = value;
invalidate();
repaint();
firePropertyChange("rowCount", old, rowCount);
}
}
public int getRowCount() {
return rowCount;
}
public void setModel(BoundedRangeModel value) {
if (value != null) {
BoundedRangeModel old = model;
model = value;
if (model != null) {
currentValue = model.getValue();
targetValue = model.getValue();
} else {
currentValue = 0;
targetValue = 0;
}
baseView = null;
firePropertyChange("model", old, model);
}
}
public BoundedRangeModel getModel() {
return model;
}
#Override
public void invalidate() {
super.invalidate();
baseView = null;
}
public float getViewOffSet(float value) {
Font font = getFont();
FontMetrics fm = getFontMetrics(font);
int rowHeight = fm.getHeight();
int extent = model.getExtent();
int min = model.getMinimum();
int max = model.getMaximum();
int viewRange = max - min;
int ticks = viewRange / extent;
float p = value / (float) viewRange;
return ((rowHeight * ticks) * p) + ((fm.getAscent() + fm.getDescent()) / 2);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage masterView = getMasterView();
if (masterView != null) {
Insets insets = getInsets();
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
int centerY = height / 2;
FontMetrics fm = g.getFontMetrics();
int yOffset = centerY - (int) getViewOffSet(currentValue);
g.drawImage(masterView, insets.left, insets.top + yOffset, this);
// Heading image...
if (yOffset > 0) {
g.drawImage(masterView, insets.left, insets.top + yOffset - masterView.getHeight(), this);
}
// Tailing image...
if (yOffset + masterView.getHeight() < height) {
g.drawImage(masterView, insets.left, insets.top + yOffset + masterView.getHeight(), this);
}
}
}
protected String pad(int value) {
StringBuilder sb = new StringBuilder(value);
sb.ensureCapacity(3);
sb.append(value);
while (sb.length() < 3) {
sb.insert(0, "0");
}
return sb.toString();
}
protected BufferedImage getMasterView() {
if (baseView == null) {
Insets insets = getInsets();
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
BoundedRangeModel model = getModel();
int extent = model.getExtent();
int min = model.getMinimum();
int max = model.getMaximum();
int viewRange = max - min;
int ticks = viewRange / extent;
Font font = getFont();
FontMetrics fm = getFontMetrics(font);
baseView = new BufferedImage(width, fm.getHeight() * ticks, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = baseView.createGraphics();
g2d.setFont(font);
g2d.setColor(Color.BLACK);
int yPos = 0;
for (int index = min; index < max; index += extent) {
String value = pad(index);
g2d.drawString(value, width - fm.stringWidth(value), yPos + fm.getAscent());
yPos += fm.getHeight();
}
}
return baseView;
}
}
public class LinearScrollerPane extends JPanel {
private BufferedImage baseView;
private BoundedRangeModel model;
private float startValue = 0;
private float currentValue = 0;
private float targetValue = 0;
private int rowCount = 3;
private Timer timer;
private long startTime;
private int runTime = 1000;
public LinearScrollerPane() {
Font font = UIManager.getFont("Label.font");
setFont(font.deriveFont(Font.BOLD, font.getSize() + 4));
setModel(new DefaultBoundedRangeModel(0, 0, 0, 20));
timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
long now = System.currentTimeMillis();
long diff = now - startTime;
if (diff >= runTime) {
((Timer) (e.getSource())).stop();
diff = runTime;
}
float progress = (float) diff / (float) runTime;
currentValue = calculateProgress(startValue, targetValue, progress);
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(false);
}
public int getValue() {
return getModel().getValue();
}
public void setValue(int value) {
timer.stop();
BoundedRangeModel model = getModel();
if (value < model.getMinimum()) {
value = model.getMinimum();
} else if (value > model.getMaximum() - model.getExtent()) {
value = model.getMaximum() - model.getExtent();
}
startValue = currentValue;
targetValue = value;
model.setValue(value);
startTime = System.currentTimeMillis();
timer.start();
}
#Override
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(getFont());
return fm == null ? super.getPreferredSize() : new Dimension(fm.stringWidth("MM"), fm.getHeight() * getRowCount());
}
public void setRowCount(int value) {
if (value != rowCount) {
int old = rowCount;
rowCount = value;
invalidate();
repaint();
firePropertyChange("rowCount", old, rowCount);
}
}
public int getRowCount() {
return rowCount;
}
public void setModel(BoundedRangeModel value) {
if (value != null) {
BoundedRangeModel old = model;
model = value;
if (model != null) {
currentValue = model.getValue();
targetValue = model.getValue();
} else {
currentValue = 0;
targetValue = 0;
}
baseView = null;
firePropertyChange("model", old, model);
}
}
public BoundedRangeModel getModel() {
return model;
}
#Override
public void invalidate() {
super.invalidate();
baseView = null;
}
public float getViewOffSet(float value) {
Font font = getFont();
FontMetrics fm = getFontMetrics(font);
int rowHeight = fm.getHeight();
int min = model.getMinimum();
int max = model.getMaximum();
int viewRange = max - min;
int ticks = getTicks();
float p = value / (float) viewRange;
return ((rowHeight * ticks) * p) + ((fm.getAscent() + fm.getDescent()) / 2);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage masterView = getMasterView();
if (masterView != null) {
Insets insets = getInsets();
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
int centerY = height / 2;
FontMetrics fm = g.getFontMetrics();
int yOffset = centerY - (int) getViewOffSet(currentValue);
g.drawImage(masterView, insets.left, insets.top + yOffset, this);
}
}
protected String pad(int value) {
StringBuilder sb = new StringBuilder(value);
sb.ensureCapacity(3);
sb.append(value);
while (sb.length() < 3) {
sb.insert(0, "0");
}
return sb.toString();
}
protected int getTicks() {
BoundedRangeModel model = getModel();
int extent = model.getExtent();
int min = model.getMinimum();
int max = model.getMaximum();
int viewRange = max - min;
int ticks = viewRange;
if (extent > 0) {
ticks = viewRange / extent;
}
return ticks;
}
protected BufferedImage getMasterView() {
if (baseView == null) {
Insets insets = getInsets();
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
BoundedRangeModel model = getModel();
int extent = model.getExtent();
int min = model.getMinimum();
int max = model.getMaximum();
int ticks = getTicks() + 1;
Font font = getFont();
FontMetrics fm = getFontMetrics(font);
baseView = new BufferedImage(width, fm.getHeight() * ticks, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = baseView.createGraphics();
g2d.setFont(font);
g2d.setColor(Color.BLACK);
int yPos = 0;
for (int index = min; index < max + 1; index += Math.max(1, extent)) {
String value = String.valueOf(index);
g2d.drawString(value, width - fm.stringWidth(value), yPos + fm.getAscent());
yPos += fm.getHeight();
}
g2d.dispose();
}
return baseView;
}
}
public static float calculateProgress(float startValue, float endValue, double fraction) {
float value = 0;
float distance = endValue - startValue;
value = (float) (distance * fraction);
value += startValue;
return value;
}
}
You can do this with a custom SliderUI, shown here, is a JSlider having a VERTICAL orientation. The example calls drawLine () in paintThumb(), but you can use TextLayout, illustrated here, to render the numbers.
I'm working on a Java program that displays a map (inherited from JComponent) within a JScrollPane. When the MouseWheelListener fires, the map zooms and the JScrollPane's viewport is adjusted to center on the location of the mouse.
This all works fine, except that the call to setSize(Dimension d) forces the map to repaint immediately before the view is adjusted, causing a "stutter." However, I cannot adjust the view until after setSize has completed execution or the calculations for "centering" the viewport will be haywire (due to getHeight() and getWidth() calls,) therefore the viewport adjustment is within a runnable called with invokeLater.
I would like to find a way to move directly from the previous map size and viewport location to the new view, without seeing the scene repainted twice.
setIgnoreRepaint(boolean) did not work for me. Is there another way to go about this?
EDIT: Here's what I worked up from your sample code that replicates my issue, although not as noticably as there's far less computation going on in the drawing. If you scroll rapidly over the image, you'll see that there's a brief stutter between the resizing of the hexagons to their new size and the adjustment of the viewport to its new position.
You can see the hexagons being re-drawn twice. (Once when the setSize() method is called and once when the setViewPosition() method is called.)
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class ZoomWithSelectionInViewport implements MouseWheelListener{
private int zoom = 80;
JComponent b;
int hexSize = 3;
public ZoomWithSelectionInViewport() throws Exception{
b = new JComponent() {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(700, 700);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = ((Graphics2D) g);
int vertOffsetX, vertOffsetY, horizOffsetX, horizOffsetY;
vertOffsetX = (int)((double)hexSize* Math.sqrt(3.0f));
vertOffsetY = (int)((double)-hexSize-1* Math.sqrt(3.0f)/2.0f);
horizOffsetX = (int) ((double)hexSize* Math.sqrt(3.0f));
horizOffsetY = (int) ((double)hexSize+1* Math.sqrt(3.0f)/2.0f);
for(int x = 0; x < 50; x++)
{
for(int y = 0; y < 50; y++)
{
int[] xcoords = new int[6]; int[] ycoords = new int[6];
for(int i = 0; i < 6; i++)
{
xcoords[i] = (int)((hexSize+x * horizOffsetX + y * vertOffsetX) + (double)hexSize * Math.cos(i * 2 * Math.PI / 6));
ycoords[i] = (int)(((getSize().height /2 )+ x * horizOffsetY + y * vertOffsetY) + (double)hexSize * Math.sin(i * 2 * Math.PI / 6));
}
g2d.setStroke(new BasicStroke(hexSize/2.5f));
g2d.setColor(Color.GRAY);
g2d.drawPolygon(xcoords, ycoords, 6);
}
}
}
};
JScrollPane view = new JScrollPane(b);
b.addMouseWheelListener(this);
JFrame f = new JFrame();
f.setLocation(10, 10);
f.setDefaultCloseOperation(3);
f.add(view);
f.setSize(500,500);
f.setVisible(true);
view.setWheelScrollingEnabled(false);
}
public void mouseWheelMoved(MouseWheelEvent e) {
zoom = 100*-Integer.signum(e.getWheelRotation());
if(hexSize - Integer.signum(e.getWheelRotation()) > 0)
hexSize-= Integer.signum(e.getWheelRotation());
Dimension targetSize = new Dimension(b.getWidth()+zoom,b.getHeight()+zoom);
b.setPreferredSize(targetSize);
b.setSize(targetSize);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JViewport tempView = (JViewport)b.getParent();
tempView.setViewPosition(new Point(b.getWidth()/2,b.getHeight()/2));
}
});
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
ZoomWithSelectionInViewport example = new ZoomWithSelectionInViewport();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
my curiosity, no idea what's happends, could you please use this SSCCE add there your issues and edit with the code your question
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class ZoomWithSelectionInViewport {
private Point startPoint = new Point(0, 0);
private Point rectLocale = new Point();
private Dimension rectSize = new Dimension();
private int zoom = 80;
private BufferedImage capture = null;
private BufferedImage raw;
public ZoomWithSelectionInViewport() throws Exception {
raw = new Robot().createScreenCapture(new Rectangle(
Toolkit.getDefaultToolkit().getScreenSize()));
MouseBehavior behavior = new MouseBehavior();
JPanel b = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(500, 500);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = ((Graphics2D) g);
g2d.drawImage(raw, 0, 0, null);
if (capture != null) {
int width2 = (int) (rectSize.width + rectSize.width * (zoom / 500d));
int height2 = (int) (rectSize.height + rectSize.height * (zoom / 500d));
int x2 = rectLocale.x - ((width2 - rectSize.width) / 2);
int y2 = rectLocale.y - ((height2 - rectSize.height) / 2);
Image scaledInstance = capture.getScaledInstance(
width2, height2, Image.SCALE_AREA_AVERAGING);
g2d.drawImage(scaledInstance, x2, y2, null);
g2d.drawRect(x2, y2, width2, height2);
} else {
g2d.draw(new Rectangle(rectLocale, rectSize));
}
}
};
b.addMouseMotionListener(behavior);
b.addMouseListener(behavior);
b.addMouseWheelListener(behavior);
JFrame f = new JFrame();
f.setLocation(10, 10);
f.setDefaultCloseOperation(3);
f.add(b);
f.pack();
f.setVisible(true);
}
private class MouseBehavior extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
rectLocale = new Point();
rectSize = new Dimension();
capture = null;
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
Point currentPoint = e.getPoint();
rectSize.width = Math.abs(currentPoint.x - startPoint.x);
rectSize.height = Math.abs(currentPoint.y - startPoint.y);
if (e.isShiftDown()) {
rectSize.width = rectSize.height = Math.min(rectSize.width, rectSize.height);
int dx = startPoint.x - rectSize.width;
int dy = startPoint.y - rectSize.height;
rectLocale.x = startPoint.x < currentPoint.x ? startPoint.x : Math.max(dx, dy);
rectLocale.y = startPoint.y < currentPoint.y ? startPoint.y : Math.min(dx, dy);
} else {
rectLocale.x = Math.min(currentPoint.x, startPoint.x);
rectLocale.y = Math.min(currentPoint.y, startPoint.y);
}
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (rectSize.width <= 0 || rectSize.height <= 0) {
capture = null;
} else {
capture = raw.getSubimage(Math.max(0, rectLocale.x),
Math.max(0, rectLocale.y), rectSize.width, rectSize.height);
}
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
zoom = Math.min(2000, Math.max(0, zoom + e.getUnitsToScroll() * 10));
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
ZoomWithSelectionInViewport example = new ZoomWithSelectionInViewport();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
an alternative could be
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
public class ZoomDemo {
private PaintSurface canvas = new PaintSurface();
private JFrame frame = new JFrame();
private AffineTransform aT = new AffineTransform();
private Point2D p1 = null;
private Point2D p2 = null;
public ZoomDemo() {
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
ScaleListener scaleListener = new ScaleListener();
canvas.addMouseWheelListener(scaleListener);
canvas.addMouseListener(scaleListener);
frame.add(canvas);
frame.setVisible(true);
}
public class ScaleListener extends MouseAdapter {
private double scale = 1;
#Override
public void mouseClicked(MouseEvent e) {
p1 = e.getPoint();
try {
p2 = aT.inverseTransform(p1, new Point2D.Double());
/*
* p1 is the point relative to canvas where the user physically
* held the mouse.
*
* Since you may want to deal with a virtual mouse location
* relative to an untransformed canvas, you inverse transform p1
* to p2.
*
* For example: when the user held the mouse over, let's say,
* the displayed left upper corner of the red rectangle.
*
* p2 now will point to the upper left corner of the red
* rectangle in an untransformed canvas.
*/
applyScale();
} catch (NoninvertibleTransformException e1) {
e1.printStackTrace();
}
canvas.repaint();
}
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (p1 != null && p2 != null) {
scale -= (0.05 * e.getWheelRotation());
if (scale > 5) {
scale = 5;
}
if (scale < 1) {
scale = 1;
aT.setToIdentity();
} else {
applyScale();
}
canvas.repaint();
}
}
private void applyScale() {
aT.setToIdentity();
// *** variation one (your implementation)
aT.translate(p1.getX(), p1.getY());
aT.scale(scale, scale);
aT.translate(-p2.getX(), -p2.getY());
// *** variation two
// aT.translate(p1.getX(), p1.getY());
// aT.scale(scale, scale);
// aT.translate(-p1.getX(), -p1.getY());
// *** variation three
// aT.translate(p2.getX(), p2.getY());
// aT.scale(scale, scale);
// aT.translate(-p2.getX(), -p2.getY());
}
}
public class PaintSurface extends JComponent {
private static final long serialVersionUID = 1L;
{
this.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
/*
* Override paintComponent, not paint!!!
*/
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
try {
g2.setColor(Color.black);
g2.fillRect(0, 0, getWidth(), getHeight());
// g2.setTransform(aT); <<<<<<<<< !!!!!!!
/*
* A transform (translation for example) may already have been
* applied to the Graphics object by a parent. This is removed
* by setTransform.
*/
g2.transform(aT); // <<<<<<<<<< !!!!!!!
g2.setColor(Color.red);
g2.drawRect(50, 50, 100, 100);
g2.setColor(Color.blue);
g2.drawRect(200, 200, 150, 50);
if (p2 != null) {
g2.setColor(Color.green);
g2.fill(new Rectangle2D.Double(p2.getX() - 4, p2.getY() - 4, 8, 8));
}
} finally {
g2.dispose();
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ZoomDemo zoomDemo = new ZoomDemo();
}
});
}
}
same question,
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
//http://stackoverflow.com/questions/6819243/jscrollpane-jumping-when-scrollbars-start-being-used
public class LockViewPortToPoint extends JFrame {
private static final long serialVersionUID = 1L;
public static void main(String[] arg) {
LockViewPortToPoint lockViewPortToPoint = new LockViewPortToPoint();
}
public LockViewPortToPoint() {
initComponents();
setVisible(true);
}
private void initComponents() {
setLayout(new BorderLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600, 600);
setPreferredSize(new Dimension(600, 600));
add(new TopPanel());
}
private class TopPanel extends JPanel {
private static final long serialVersionUID = 1L;
private JScrollPane scrollPane;
TopPanel() {
setPreferredSize(new Dimension(500, 500));
scrollPane = new JScrollPane(new InteriorPanel());
scrollPane.setPreferredSize(new Dimension(500, 500));
scrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(10, 490));
scrollPane.getHorizontalScrollBar().setPreferredSize(new Dimension(490, 10));
scrollPane.setWheelScrollingEnabled(false);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scrollPane);
}
}
private class InteriorPanel extends JPanel {
private static final long serialVersionUID = 1L;
private double scale = 10.0;
private final double scaleModifier = 0.1;
private final int width = 10;
private Point loc = new Point(0, 0);
private final int SIZE = 10;
private Point orig = new Point(250, 250);
InteriorPanel() {
super(true);
setPreferredSize(new Dimension((int) (scale * width * SIZE), (int) (scale * width * SIZE)));
this.addMouseWheelListener(new MapMouseWheelListener());
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2D.scale(scale, scale);
for (int row = 0; row <= SIZE; row++) {
for (int col = 0; col < SIZE; col++) {
if ((col + row) % 2 == 0) {
g2D.setColor(Color.white);
} else {
g2D.setColor(Color.black);
}
g2D.fillRect(col * width, row * width, width, width);
}
}
}
private void incrementScale(int notches) {
double modifier = 0;
final double prevScale = scale;
if (notches != 0) {
modifier = 1.0 + -notches / Math.abs(notches) * scaleModifier;
}
scale *= Math.pow(modifier, Math.abs(notches));
/*if (scale * width < 1) {
scale = 1.0/width;
} else if (scale * width * 3 > parentHeight || scale * width * 3 > parentWidth) {
if (parentHeight > parentWidth) {
scale = parentWidth / 3.0 / width;
} else {
scale = parentHeight / 3.0 / width;
}
} else if (scale * width * SIZE < parentWidth) {
scale = parentWidth / (double)SIZE / width;
} else if (scale * width * SIZE < parentHeight) {
scale = parentHeight / (double)SIZE / width;
}*/
setPreferredSize(new Dimension((int) (scale * width * SIZE), (int) (scale * width * SIZE)));
orig = new Point(((int) (scale * width * SIZE)) / 2, ((int) (scale * width * SIZE) / 2));
final JViewport viewport = ((JViewport) (getParent().getParent().getComponent(0)));
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
viewport.setViewPosition(new Point(
orig.x - (int) Math.round(loc.x * (1 - scale / prevScale)),
orig.y - (int) Math.round(loc.y * (1 - scale / prevScale))));
}
});
/*viewport.scrollRectToVisible(new Rectangle(new Point(
orig.x - (int) Math.round(loc.x * (1 - scale / prevScale)),
orig.y - (int) Math.round(loc.y * (1 - scale / prevScale))))); */
System.out.println(orig + "\n " + loc + "\n " + (1 - scale / prevScale));
revalidate();
repaint();
}
private class MapMouseWheelListener implements MouseWheelListener {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
loc = e.getPoint();
incrementScale(e.getWheelRotation());
}
}
}
}
another example
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
//http://stackoverflow.com/questions/115103/how-do-you-implement-position-sensitive-zooming-inside-a-jscrollpane
public class FPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private Dimension preferredSize = new Dimension(400, 400);
private Rectangle2D[] rects = new Rectangle2D[50];
public static void main(String[] args) {
JFrame jf = new JFrame("test");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(400, 400);
jf.add(new JScrollPane(new FPanel()));
jf.setVisible(true);
}
public FPanel() {
// generate rectangles with pseudo-random coords
for (int i = 0; i < rects.length; i++) {
rects[i] = new Rectangle2D.Double(
Math.random() * .8, Math.random() * .8,
Math.random() * .2, Math.random() * .2);
}
// mouse listener to detect scrollwheel events
addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
updatePreferredSize(e.getWheelRotation(), e.getPoint());
}
});
}
private void updatePreferredSize(int wheelRotation, Point stablePoint) {
double scaleFactor = findScaleFactor(wheelRotation);
scaleBy(scaleFactor);
Point offset = findOffset(stablePoint, scaleFactor);
offsetBy(offset);
getParent().doLayout();
revalidate();
repaint();
}
private double findScaleFactor(int wheelRotation) {
double d = wheelRotation * 1.08;
return (d > 0) ? 1 / d : -d;
}
private void scaleBy(double scaleFactor) {
int w = (int) (getWidth() * scaleFactor);
int h = (int) (getHeight() * scaleFactor);
preferredSize.setSize(w, h);
}
private Point findOffset(Point stablePoint, double scaleFactor) {
int x = (int) (stablePoint.x * scaleFactor) - stablePoint.x;
int y = (int) (stablePoint.y * scaleFactor) - stablePoint.y;
return new Point(x, y);
}
private void offsetBy(Point offset) {
Point location = getLocation();
setLocation(location.x - offset.x, location.y - offset.y);
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
private Rectangle2D r = new Rectangle2D.Float();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
int w = getWidth();
int h = getHeight();
for (Rectangle2D rect : rects) {
r.setRect(rect.getX() * w, rect.getY() * h,
rect.getWidth() * w, rect.getHeight() * h);
((Graphics2D) g).draw(r);
}
}
}
I need to draw a curve, knowing that I receive points every x milliseconds or x seconds, and that the curve is moving to the left by one pixel each time I receive a new point. I'm using the Bezier algorithm to draw the curve from the points I receive, so I need at least three points to start. I would like to know how to proceed to draw the curve bit by bit on an image.
This is what I'm doing right now:
int xPos = 0;
Point2D.Double[] points = new Point2D.Double[listYpos.size()];
for (int i = 0; i < listYpos.size(); i++) {
points[i] = new Point2D.Double(i, listYpos.get(i));
}
if (curveImg == null) {
curveImg = gc.createCompatibleImage(imageWidth, imageHeight, Transparency.BITMASK);
}
if (points.length > 3) {
Graphics2D gImg = (Graphics2D) curveImg.getGraphics();
renderCurve(gImg, Arrays.copyOfRange(points, listYpos.size() - 4, listYpos.size() - 1));
gImg.dispose();
}
AffineTransform at = g.getTransform();
at.scale(-1, 1);
at.translate(-xPos++, listYpos.get(listYpos.size() - 1));
g.drawImage(curveImg, at, null);
This method is called each time a new point is received every x milliseconds or x seconds.
I think that gImg.dispose();
maybe this code can help you with that (from old.forums.sun.com)
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
import javax.swing.*;
public class BezierTest {
private class Animator implements ActionListener {
private double distance = 0;
private boolean moveTo = true;
private ArrayList<Point2D> points = new ArrayList<Point2D>();
private double step = -1;
private double steps;
private Timer timer = new Timer(0, this);
#Override
public void actionPerformed(ActionEvent e) {
step++;
if (step <= steps) {
double t = step / steps;
Point2D newPoint = computeBezierPoint(new Point2D.Double(), t, curvePoints);
marks[marks.length - 1].setFrame(newPoint.getX() - 5, newPoint.getY() - 5, 10, 10);
points.add(newPoint);
if (moveTo) {
path.moveTo(newPoint.getX(), newPoint.getY());
moveTo = false;
} else {
path.lineTo(newPoint.getX(), newPoint.getY());
}
lines[3] = new Line2D.Double(computePointOnLine(lines[0], t), computePointOnLine(lines[1], t));
lines[4] = new Line2D.Double(computePointOnLine(lines[1], t), computePointOnLine(lines[2], t));
lines[5] = new Line2D.Double(computePointOnLine(lines[3], t), computePointOnLine(lines[4], t));
// The maximum distance encountered between the results of two calculation methods.
// newPoint from computeBezierPoint() the other via the lines method
distance = Math.max(distance, newPoint.distance(computePointOnLine(lines[5], t)));
demoComponent.repaint();
} else {
timer.stop();
animationButton.setEnabled(true);
if (distance > 0d) {
System.out.println("Maximum difference " + distance);
}
}
}
public void init() {
timer.stop();
animationButton.setEnabled(false);
steps = sliderStep.getValue();
step = -1;
distance = 0;
moveTo = true;
path = new Path2D.Double();
int sleepTime = (int) Math.round(1000d * sliderDuration.getValue() / steps);
timer.setDelay(sleepTime);
timer.setInitialDelay(0);
timer.start();
}
private Point2D computeBezierPoint(Point2D rv, double t,
Point2D... curve) {
if (rv == null) {
rv = new Point2D.Double();
} else {
rv.setLocation(0, 0);
}
int n = curve.length - 1;
double oneMinusT = 1.0 - t;
for (int index = 0; index < curve.length; index++) {
double multiplier = index == 0 || index == n ? 1 : StrictMath.min(n - index, index) * n;
multiplier *= StrictMath.pow(t, index) * StrictMath.pow(oneMinusT, n - index);
rv.setLocation(rv.getX() + multiplier * curve[index].getX(), rv.getY() + multiplier * curve[index].getY());
}
return rv;
}
private Point2D computePointOnLine(Line2D line, double t) {
return new Point2D.Double((line.getX2() - line.getX1()) * t + line.getX1(), (line.getY2() - line.getY1()) * t + line.getY1());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new BezierTest().createGUI();
}
});
}
private final JButton animationButton = new JButton(new AbstractAction("Start animation") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
animator.init();
}
});
private final Animator animator = new Animator();
private Point2D[] curvePoints = new Point2D[]{new Point(10, 50), new Point(190, 10), new Point(190, 190), new Point(10, 150)};
private JComponent demoComponent = new JComponent() {
private static final long serialVersionUID = 1L;
{
setPreferredSize(new Dimension(400, 400));
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
int w = getWidth();
int h = getHeight();
recalculateAfterResize(w, h);
}
});
}
#Override
protected void paintComponent(Graphics g) {
if (isVisible()) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
paintBezier(g);
}
}
};
private Line2D[] lines = new Line2D[6];
private final Ellipse2D[] marks;
private Path2D path;
private final JSlider sliderDuration = createSlider(1, 20, 2, "Duration in seconds", 9, 1);
private final JSlider sliderStep = createSlider(8, 128, 64, "Animation steps", 16, 1);
private Path2D totalCurve;
{
marks = new Ellipse2D[curvePoints.length + 1];
for (int index = 0; index < marks.length; index++) {
marks[index] = new Ellipse2D.Double();
}
}
private void createGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(demoComponent, BorderLayout.CENTER);
JToolBar toolBar = new JToolBar();
toolBar.add(animationButton);
toolBar.add(sliderStep);
toolBar.add(sliderDuration);
frame.add(toolBar, BorderLayout.PAGE_START);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
private JSlider createSlider(int min, int max, int value, String title, int major, int minor) {
JSlider slider = new JSlider(min, max, value);
slider.setBorder(BorderFactory.createTitledBorder(title));
slider.setMajorTickSpacing(major);
// slider.setMinorTickSpacing(minor);
slider.setPaintLabels(true);
slider.setPaintTicks(true);
return slider;
}
private void paintBezier(Graphics g) {
Path2D path1 = this.path;
if (path1 != null) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.GREEN);
for (Shape mark : marks) {
g2.fill(mark);
}
g2.setStroke(new BasicStroke(2f));
g2.setColor(Color.BLACK);
for (Shape mark : marks) {
g2.draw(mark);
}
g2.setStroke(new BasicStroke(0f));
g2.draw(totalCurve);
g2.setStroke(new BasicStroke(1f));
g2.setColor(Color.RED);
g2.draw(path1);
g2.setStroke(new BasicStroke(.5f));
g2.setColor(Color.BLACK);
for (Line2D line : lines) {
if (line != null) {
g2.draw(line);
}
}
}
}
private void recalculateAfterResize(int w, int h) {
curvePoints = new Point2D[]{new Point2D.Double(10, h / 4.0), new Point2D.Double(w - 10, 10), new Point2D.Double(w - 10, h - 10), new Point2D.Double(10, h - h / 4.0)};
totalCurve = new Path2D.Double();
totalCurve.moveTo(curvePoints[0].getX(), curvePoints[0].getY());
totalCurve.curveTo(curvePoints[1].getX(), curvePoints[1].getY(), curvePoints[2].getX(), curvePoints[2].getY(), curvePoints[3].getX(), curvePoints[3].getY());
for (int index = 0; index < curvePoints.length; index++) {
marks[index].setFrame(curvePoints[index].getX() - 5, curvePoints[index].getY() - 5, 10, 10);
}
marks[marks.length - 1].setFrame(marks[0].getFrame());
for (int index = 0; index < curvePoints.length - 1; index++) {
lines[index] = new Line2D.Double(curvePoints[index], curvePoints[index + 1]);
}
lines[3] = null;
lines[4] = null;
lines[5] = null;
animator.init();
}
}