Jump to content
claudiop

Problemas com JScrollPane a usar Java2D

Recommended Posts

claudiop

Boas.

Eu tenho um programa que estou a fazer, que necessito que fassa render de objectos graficos dentro de uma area "scrollable".

O problema é que ainda só coloquei uma imagem simples e já vejo problemas a aparecer, o scroll faz isto:

Do9Il4R.png

PS: A img é esta: http://www.rarst.net/images/android-tablet-wallpaper-size/android_wallpaper_template_1920x1408.png

Como é que posso corrigir isto?

Aqui está o codigo que está a fazer o render dentro de um JPanel:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Render extends JPanel{
 Render(){
   super();
 }
 @Override
 public void paint(Graphics g){
   Graphics2D graphObj=(Graphics2D) g;
   BufferedImage environment = null;
   try {
     environment = ImageIO.read(new File("/caminho/para/a/img"));
   } catch (IOException e) {
     JOptionPane.showMessageDialog(null, "Não foi possivel carregar a imagem!");
   }
   Dimension environmentSize = getImageSize(environment);
   super.setPreferredSize(environmentSize);
   graphObj.drawImage(environment, 0, 0, null);
 }
 private Dimension getImageSize(BufferedImage img){
   Dimension imgSize = new Dimension(img.getWidth(),img.getHeight());
   return imgSize;
 }
}

E já agora, se alguem quiser contribuir com ajuda adicional, aceitava um exemplo de como implementar a habilidade de pan e zoom, mesmo que abstractamente.

Cumprimentos


When you have nothing to do, try thinking about thinking. mind(){mind();}

Share this post


Link to post
Share on other sites
Ernest

Bom dia,

Versão simplificada ao extremo :

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;

public class ScrollPaneDemo extends JFrame
{

   public ScrollPaneDemo()
   {
       super("JScrollPane Imagem");
       ImageIcon imagenIcon = new ImageIcon("android_wallpaper_template_1920x1408.png");
       JScrollPane jsp = new JScrollPane(new JLabel(imagenIcon));
       getContentPane().add(jsp);
       setSize(1500, 700);
       setVisible(true);
   }

   public static void main(String[] args) {
        new ScrollPaneDemo();
   }
}

Também tem um bocado mais elaborado mas é para depois ...

  • Vote 1

Share this post


Link to post
Share on other sites
claudiop

Bom dia,

Versão simplificada ao extremo :

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;

public class ScrollPaneDemo extends JFrame
{

   public ScrollPaneDemo()
   {
       super("JScrollPane Imagem");
       ImageIcon imagenIcon = new ImageIcon("android_wallpaper_template_1920x1408.png");
       JScrollPane jsp = new JScrollPane(new JLabel(imagenIcon));
       getContentPane().add(jsp);
       setSize(1500, 700);
       setVisible(true);
   }

   public static void main(String[] args) {
        new ScrollPaneDemo();
   }
}

Também tem um bocado mais elaborado mas é para depois ...

Muito obrigado pela sua ajuda.

De facto o seu codigo funciona bastante fluido e não cria erros graficos no scroll. O quê é que os estaria a causar, a bufferedImage?

Existe alguma desvantagem em utilizar o ImageIcon com uma imagem de elevado tamanho e dimensões?

Já exprimentei a imagem a ser utilizada(que tem mais de 15000 pixeis de largura por 4000) e funcionou perfeitamente, mas estranhamente o processo do programa não consumia quase memoria nenhuma.

Posso aplicar em ImageIcon's as transformações que são aplicaveis nas BufferedImage's para implementar pan e zoom?(resizes on-the-go)

Cumprimentos


When you have nothing to do, try thinking about thinking. mind(){mind();}

Share this post


Link to post
Share on other sites
Ernest

Bom dia,

A partir de um BufferedImage também se pode fabricar um ImageIcon.

O problema é que SWING é baseado no AWT, foi por isso que ECLIPSE foi baseado pela IBM no SWT/JFace que já é melhore mas tem o problema da portabilidade 100%.

JavaFX também é muito potente.

A diferença fundamentalmente entre o seu código e o meu é que eu não utilizo por enquanto : paint(Graphics g) , paintComponent(Graphics g) , drawImage(..)

Uma coisa deste gênero :

@Override
   protected void paintComponent(Graphics g) {
       super.paintComponent(g);
       g.drawImage(image, 0, 0, null);         
   }

O problema com estes métodos (call Back) paint(Graphiocs g) é que não são previsíveis por serem assíncronos. Nunca se sabe quando serão chamados ...

Aqui esta uma versão mais completa :

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;


public class ImageApp extends JPanel {

private static final long serialVersionUID = 1L;


public ImageApp(JFrame frameParent)
{
   ImageIcon imageIcon = createImageIcon("android_wallpaper_template_1920x1408.png");

   JLabel labelImg = new JLabel(imageIcon);
   labelImg.setHorizontalAlignment(JLabel.CENTER);

   JScrollPane jsp = new JScrollPane(labelImg);

   frameParent.getContentPane().add(jsp);
}

protected ImageIcon createImageIcon(String image)
{
   BufferedImage bufImg = null;
   try {

       bufImg = ImageIO.read(new File(image));
       Dimension environmentSize = getImageSize(bufImg);
       super.setPreferredSize(environmentSize);

   } catch (IOException e) {
       e.printStackTrace();
   }
   if (bufImg != null) {
       return new ImageIcon(bufImg);
   } else {
       JOptionPane.showMessageDialog(null, "Não encontra a imagem : " + image);
       return null;
   }
}


private Dimension getImageSize(BufferedImage img){
   Dimension imgSize = new Dimension(img.getWidth(),img.getHeight());
   return imgSize;
}


private static void createAndShowGUI()
{
   JFrame frameParent = new JFrame("Image App");
   frameParent.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

   new ImageApp(frameParent);

   frameParent.setBounds(10, 10, 1000, 800);
   frameParent.setVisible(true);
}


public static void main(String[] args)
{
   javax.swing.SwingUtilities.invokeLater(new Runnable() {
       public void run() {
           createAndShowGUI();
       }
   });
}
}

No Eclipse pode fazer no teclado Ctrl + i para Indentation do código.

Repare que eu envio a frameParent no constructor do JPanel o que lhe permite utilizar o JPanel ImageApp em qualquer JFrame.

Repare também que o código no método main(String[] args) faz parte das boas práticas SWING descritas no Web Site da ORACLE / SUN .

Conclusão

Utilize o Eclipse Kepler (4.3) sobre Java Platform (JDK 1.7_25) com o Google Plugin for Eclipse e o WindowBuilder Pro.

Desenvolver interfaces gráficas Java em 5 minutos para : Swing, SWT, RCP, XWT e GWT com WindowBuilder Pro WYSIWYG, drag-and-drop interface.

A moda é d'utilizar JavaFX que vem integrado no JDK : What Is JavaFX ?

http://docs.oracle.com/javafx/2/overview/jfxpub-overview.htm

Mais tarde mostro como fazer o resto , pan, zoom e muito mais com JavaFX e SWING é muito fácil ...

Cordialmente

Ernest Duarte

Share this post


Link to post
Share on other sites
claudiop

Bom dia,

A partir de um BufferedImage também se pode fabricar um ImageIcon.

O problema é que SWING é baseado no AWT, foi por isso que ECLIPSE foi baseado pela IBM no SWT/JFace que já é melhore mas tem o problema da portabilidade 100%.

JavaFX também é muito potente.

A diferença fundamentalmente entre o seu código e o meu é que eu não utilizo por enquanto : paint(Graphics g) , paintComponent(Graphics g) , drawImage(..)

Uma coisa deste gênero :

@Override
   protected void paintComponent(Graphics g) {
       super.paintComponent(g);
       g.drawImage(image, 0, 0, null);         
   }

O problema com estes métodos (call Back) paint(Graphiocs g) é que não são previsíveis por serem assíncronos. Nunca se sabe quando serão chamados ...

Aqui esta uma versão mais completa :

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;


public class ImageApp extends JPanel {

private static final long serialVersionUID = 1L;


public ImageApp(JFrame frameParent)
{
   ImageIcon imageIcon = createImageIcon("android_wallpaper_template_1920x1408.png");

   JLabel labelImg = new JLabel(imageIcon);
   labelImg.setHorizontalAlignment(JLabel.CENTER);

   JScrollPane jsp = new JScrollPane(labelImg);

   frameParent.getContentPane().add(jsp);
}

protected ImageIcon createImageIcon(String image)
{
   BufferedImage bufImg = null;
   try {

       bufImg = ImageIO.read(new File(image));
       Dimension environmentSize = getImageSize(bufImg);
       super.setPreferredSize(environmentSize);

   } catch (IOException e) {
       e.printStackTrace();
   }
   if (bufImg != null) {
       return new ImageIcon(bufImg);
   } else {
       JOptionPane.showMessageDialog(null, "Não encontra a imagem : " + image);
       return null;
   }
}


private Dimension getImageSize(BufferedImage img){
   Dimension imgSize = new Dimension(img.getWidth(),img.getHeight());
   return imgSize;
}


private static void createAndShowGUI()
{
   JFrame frameParent = new JFrame("Image App");
   frameParent.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

   new ImageApp(frameParent);

   frameParent.setBounds(10, 10, 1000, 800);
   frameParent.setVisible(true);
}


public static void main(String[] args)
{
   javax.swing.SwingUtilities.invokeLater(new Runnable() {
       public void run() {
           createAndShowGUI();
       }
   });
}
}

No Eclipse pode fazer no teclado Ctrl + i para Indentation do código.

Repare que eu envio a frameParent no constructor do JPanel o que lhe permite utilizar o JPanel ImageApp em qualquer JFrame.

Repare também que o código no método main(String[] args) faz parte das boas práticas SWING descritas no Web Site da ORACLE / SUN .

Conclusão

Utilize o Eclipse Kepler (4.3) sobre Java Platform (JDK 1.7_25) com o Google Plugin for Eclipse e o WindowBuilder Pro.

Desenvolver interfaces gráficas Java em 5 minutos para : Swing, SWT, RCP, XWT e GWT com WindowBuilder Pro WYSIWYG, drag-and-drop interface.

A moda é d'utilizar JavaFX que vem integrado no JDK : What Is JavaFX ?

http://docs.oracle.com/javafx/2/overview/jfxpub-overview.htm

Mais tarde mostro como fazer o resto , pan, zoom e muito mais com JavaFX e SWING é muito fácil ...

Cordialmente

Ernest Duarte

Infelizmente devo de ter mesmo de utilizar o Java 2D, até porque tenho que desenhar "na" imagem.

Já sei assim por alto como é que funciona, enquanto que Java FX não sei nada de nada, e visto que tenho prazo torna-se inviavel(só tenho semana e meia para ter algo a funcionar razoavelmente bem).

Fiz uma "aldrabisse" para fazer o zoom o que acho não ser de todo correcto. Quando o programa inicia cria runnables para guardar em variaveis imagens já reduzidas por factores pre-definidos. Tirar zoom por tanto é apenas trocar de imagem. É muito mau fazer isso?

Esta ajuda em especifico que estou a pedir é para uma aplicação que abre panoramas de alta resolução, e permite adicionar pontos de intresse nos mesmos, marcando-os na imagem com simbolos, os quais são interactivos para mostrarem mais informação. Tudo isso guardado numa base de dados SQLite que segue num package com cada grupo de imagens panoramicas(possivelmente farei um .tar com os dois numa extenção propria).

Se tiver soluções melhores ou inisitir no Java FX tem de compensar realmente para este caso em especifico, pois porque não penso dar grande utilidade ao java de futuro. Perfiro linguagens compiladas em binario.

Cumprimentos


When you have nothing to do, try thinking about thinking. mind(){mind();}

Share this post


Link to post
Share on other sites
Ernest

Bom dia,

Exemplo com AffineTransform.getScaleInstance quando utiliza o Slider (tem que esperar um bucado para o tratamento da Tranformação Afina) e também pode mover imagem com o rato. Agora falta meter os Markers interactivos como no Google Maps.


import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JViewport;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


/**
* Exemplo de zooming e panning com jScrollPane
*
* @author Ernest Duarte
*
*/
public class PanZoomImagem2 implements ChangeListener
{
   BufferedImage image;
   JLabel label;

   public void stateChanged(ChangeEvent e)
   {
       int value = ((JSlider)e.getSource()).getValue();
       double scale = value/100.0;
       BufferedImage scaled = getScaledImage(scale);
       label.setIcon(new ImageIcon(scaled));
       label.revalidate();
   }

   private BufferedImage getScaledImage(double scale) {
       int w = (int)(scale*image.getWidth());
       int h = (int)(scale*image.getHeight());
       BufferedImage bi = new BufferedImage(w, h, image.getType());
       Graphics2D g2 = bi.createGraphics();
       g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
       RenderingHints.VALUE_INTERPOLATION_BICUBIC);
       AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
       g2.drawRenderedImage(image, at);
       g2.dispose();
       return bi;
   }

   private JLabel getContent(String nameImage) {
       createAnImage2(nameImage);
       label = new JLabel(new ImageIcon(image));
       label.setHorizontalAlignment(JLabel.CENTER);
       return label;
   }


   private void createAnImage2(String nameImage)
   {
       try {
           image = ImageIO.read(new File(nameImage));
       } catch (IOException e) {
           e.printStackTrace();
       }
   }

   private JSlider getControl() {
       JSlider slider = new JSlider(JSlider.HORIZONTAL, 50, 200, 100);
       slider.setMajorTickSpacing(50);
       slider.setMinorTickSpacing(10);
       slider.setPaintTicks(true);
       slider.setPaintLabels(true);
       slider.addChangeListener(this);
       return slider;
   }

   static class HandScrollListener extends MouseAdapter
   {
       private final Point pp = new Point();

       @Override
       public void mouseDragged(MouseEvent e) {
           JViewport vport = (JViewport)e.getSource();
           JComponent label = (JComponent)vport.getView();
           Point cp = e.getPoint();
           Point vp = vport.getViewPosition();
           vp.translate(pp.x-cp.x, pp.y-cp.y);
           label.scrollRectToVisible(new Rectangle(vp, vport.getSize()));
           vport.setViewPosition(vp);
           pp.setLocation(cp);
       }
       @Override public void mousePressed(MouseEvent e) {
           pp.setLocation(e.getPoint());
       }
   }


   public static void main(String[] args) {
       PanZoomImagem2 app = new PanZoomImagem2();
       JFrame f = new JFrame();
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

       JScrollPane jScrollPane = new JScrollPane(app.getContent("android_wallpaper_template_1920x1408.png"));

       //--------------- HandScrollListener
       JViewport vport = jScrollPane.getViewport();
       MouseAdapter ma = new HandScrollListener();
       vport.addMouseMotionListener(ma);
       vport.addMouseListener(ma);

       //-------------

       f.getContentPane().add(jScrollPane);

       f.getContentPane().add(app.getControl(), "Last");
       f.setSize(400, 400);
       f.setLocation(200,200);
       f.setVisible(true);
   }
} 

Cordialmente

Ernest Duarte

Edited by Rui Carlos

Share this post


Link to post
Share on other sites
claudiop

Boas.

Como novato que sou, demorei estes dois dias a tentar ler o seu codigo, até que pareçe que entendi(não me entendia com o ChangeListener).

Tentei integrar o codigo dentro da estrutura do meu programa mas não estou a conseguir. Tenho as seguintes classes a dar uso ao seu codigo:

Interface.java(Codigo encurtado para reflectir apenas o essencial):

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import javax.swing.JSplitPane;
import javax.swing.JPanel;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JSlider;
import java.awt.FlowLayout;

public class Interface {
private JFrame mainFrame;
public static void main(String[] args) {
 EventQueue.invokeLater(new Runnable() {
  public void run() {
   try {Interface window = new Interface();window.mainFrame.setVisible(true);
       } catch (Exception e) { e.printStackTrace();}
  }
 });
}
public Interface() {initialize();}
private void initialize() {
 mainFrame = new JFrame();
 mainFrame.setTitle("LXView");
 mainFrame.setMinimumSize(new Dimension(800, 600));
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 mainFrame.setExtendedState(mainFrame.getExtendedState()| JFrame.MAXIMIZED_BOTH);
 mainFrame.getContentPane().setBackground(Color.WHITE);
 mainFrame.getContentPane().setLayout(new BorderLayout(0, 0));
 JSplitPane splitPane = new JSplitPane();
 splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
 splitPane.setOneTouchExpandable(true);
 splitPane.setBackground(Color.WHITE);
 mainFrame.getContentPane().add(splitPane, BorderLayout.CENTER);
 splitPane.setResizeWeight(0.99);
 JScrollPane scrollPane = new JScrollPane();
 scrollPane.setEnabled(false);
 splitPane.setLeftComponent(scrollPane);
 Render topPane = new Render();
 scrollPane.setViewportView(topPane);
 topPane.setLayout(new BoxLayout(topPane, BoxLayout.X_AXIS));
 JPanel botPane = new JPanel();
 splitPane.setRightComponent(botPane);
 botPane.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
 JLabel zoomLevel = new JLabel("Zoom level:");
 botPane.add(zoomLevel);
 JSlider slider = new JSlider(JSlider.HORIZONTAL, 25, 100, 100);
 slider.setMajorTickSpacing(15);
 slider.setMinorTickSpacing(5);
 slider.setPaintTicks(true);
 slider.setPaintLabels(true);
 slider.setPreferredSize(new Dimension(600,40));
 botPane.add(slider);
 PanAndZoom zoomer=new PanAndZoom(topPane.getLabel());
 slider.addChangeListener(zoomer);
}
}

Render.java(idem aspas):

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Render extends JPanel {
JLabel envContainer;
Render() {
 super();
 ImageIcon imageIcon = new ImageIcon("/caminho/para/imagem");
 JLabel envContainer = new JLabel(imageIcon);
 super.add(envContainer);
}
@Override
public void paint(Graphics g) {
 super.paint(g);
 /*Renderizações*/
}
public JLabel getLabel() {
 return envContainer;
}
}

PanAndZoom.java

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class PanAndZoom implements ChangeListener {
private JLabel label;
private BufferedImage image;


public PanAndZoom(JLabel lab){
 this.label=lab;
 try {
  image = ImageIO.read(new File("/caminho/para/imagem"));
 } catch (IOException e) {
  e.printStackTrace();
 }
 label.setIcon(new ImageIcon("/caminho/para/outra/imagem"));//Para testar trocar a imagem do icon. Dá erro!
}
public void stateChanged(ChangeEvent e) {
 int value = ((JSlider) e.getSource()).getValue();
 double scale = value / 100.0;
 BufferedImage scaled = getScaledImage(scale); // Dá erro
 System.out.println("Scale:"+scale+" Value:"+value);
 label.setIcon(new ImageIcon(scaled));
 label.revalidate();

}
private BufferedImage getScaledImage(double scale) {
 int w = (int) (scale * image.getWidth());
 int h = (int) (scale * image.getHeight());
 BufferedImage bi = new BufferedImage(w, h, image.getType());
 Graphics2D g2 = bi.createGraphics();
 g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
 AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
 g2.drawRenderedImage(image, at);
 g2.dispose();
 return bi;
}
}

Os dois erros que tive (e assinalei), encontram-se relacionados com o acesso (ou falta dele) á JLabel que foi retornada pelo "getLabel()"[Render.java].

Se eu receber numa classe diferente uma LJabel já criada, e a associar a uma variavel, esse variavel não deveria de manter uma referencia ao JLabel da classe original?

Cumprimentos e muito obrigado pelo seu codigo


When you have nothing to do, try thinking about thinking. mind(){mind();}

Share this post


Link to post
Share on other sites
Ernest

Bom dia,

Este programa tem só um erro de funcionamento :

Tem um erro na classe Render.java :

JLabel envContainer; // equivalente a JLabel envContainer = null;

.....

JLabel envContainer = new JLabel(imageIcon); /// tem que tirar este JLabel em vermelho que está a esconder o primeiro lá encima

.....

Se não, conclusão : getLabel() return NullPointerException

-------------------------------

Chamar uma classe de Interface é possível mas não é muito claro na leitora de um programa Java ou até mesmo C#.

Para um desenvolvedor java com mais de 10 anos de experiencia, até arrepia de ver esta frase : Interface window = new Interface(); Mesmo se está certo.

Não é muito aconselhável de usar, já que existe uma palavra chave em Java : interface

E que não se pode Instanciar uma interface em Java. Mesmo se está certo. Não é muito claro e pode criar confusões.

Por que não escolher um outro nome como por exemplo VistaPrincipale.java ou MainFrame ou IHM ... etc.

A escolha nos nomes corretos de variáveis é fundamental na resolução de um problema matemático e talvez ainda muito mais na implementação sem erros de um algoritmo informático.

------------------------------

Outra coisa importante é a arquitetura do programa informático. Um programa de computador é como uma casa, se não tiver uma boa arquitetura desde o início, pode entrar em colapso.

Uma das regras é cada coisa no seu logar, separation of concerns (SoC).

---------------------------

Agora Já não dá erro ! até funciona bem fluido e rápido no meu ordinateur (ordinator, computador).

Pena não ter integrado a navegação com o rato do computador para navegar na imagem como no Google Maps.

---------------------------------------

Para meter Point Of Interest (POI) nas imagens com um marker, como é o caso por exemplo no Google Maps.

Uma solução simples é de preparar a imagem com pontos : Point Of Interest (POI) por exemplo provenientes de um ficheiro XML ( com as coordenadas latitude x, longitude y).

Nessas posições (x , y) sobrepor uma pequena imagem (ou desenhá-la com Graphics g) e depois é so passar o rato por sima para ela reagir (gestão eventos... Design Pattern Observer) e mostrar informações suplementares sobre esse Point Of Interest (POI) .

Depois é só fazer a mesma coisa com a nova imagem tratada com os POI.

Com JAVA é muito fácil de programar :-)

Cordialmente

Ernest Duarte

Edited by Ernest Duarte

Share this post


Link to post
Share on other sites
claudiop

Bom dia,

Este programa tem só um erro de funcionamento :

Tem um erro na classe Render.java :

JLabel envContainer; // equivalente a JLabel envContainer = null;

.....

JLabel envContainer = new JLabel(imageIcon); /// tem que tirar este JLabel em vermelho que está a esconder o primeiro lá encima

.....

Se não, conclusão : getLabel() return NullPointerException

-------------------------------

Chamar uma classe de Interface é possível mas não é muito claro na leitora de um programa Java ou até mesmo C#.

Para um desenvolvedor java com mais de 10 anos de experiencia, até arrepia de ver esta frase : Interface window = new Interface(); Mesmo se está certo.

Não é muito aconselhável de usar, já que existe uma palavra chave em Java : interface

E que não se pode Instanciar uma interface em Java. Mesmo se está certo. Não é muito claro e pode criar confusões.

Por que não escolher um outro nome como por exemplo VistaPrincipale.java ou MainFrame ou IHM ... etc.

A escolha nos nomes corretos de variáveis é fundamental na resolução de um problema matemático e talvez ainda muito mais na implementação sem erros de um algoritmo informático.

------------------------------

Outra coisa importante é a arquitetura do programa informático. Um programa de computador é como uma casa, se não tiver uma boa arquitetura desde o início, pode entrar em colapso.

Uma das regras é cada coisa no seu logar, separation of concerns (SoC).

---------------------------

Agora Já não dá erro ! até funciona bem fluido e rápido no meu ordinateur (ordinator, computador).

Pena não ter integrado a navegação com o rato do computador para navegar na imagem como no Google Maps.

---------------------------------------

Para meter Point Of Interest (POI) nas imagens com um marker, como é o caso por exemplo no Google Maps.

Uma solução simples é de preparar a imagem com pontos : Point Of Interest (POI) por exemplo provenientes de um ficheiro XML ( com as coordenadas latitude x, longitude y).

Nessas posições (x , y) sobrepor uma pequena imagem (ou desenhá-la com Graphics g) e depois é so passar o rato por sima para ela reagir (gestão eventos... Design Pattern Observer) e mostrar informações suplementares sobre esse Point Of Interest (POI) .

Depois é só fazer a mesma coisa com a nova imagem tratada com os POI.

Com JAVA é muito fácil de programar :-)

Cordialmente

Ernest Duarte

Muito obrigado por me ajudar a encontrar o erro. não fazia a minima ideia que uma classe pudesse ter duas variaveis com o mesmo nome independentes, mesmo que dentro de um metodo/constructor.

Vou já fazer refactor nesse caso. Por acaso já tinha visto isso das "Interfaces", mas não me lembrei ou não tinha visto quando dei o nome á classe.

A integração do pan vou faze-la tambem, mas só depois de fazer o sistema de Action Handlers(acho que é assim que se chama) que vão determinar onde é que o rato está, e se há o que fazer. Á partida devo de fazer isso a partir de uma list/array de cordenadas, e um listener na posição de rato sobre o painel da imagem.

O pan só tinha um pequeno bug(que espero conseguir corrigir) que deixava a imagem ser arrastada indefinidamente para cima e para a esquerda, mas não é grave e devo de conseguir encontrar o erro com facilidade(espero eu).

Sim, está relativamente fluido, mas as imagens a ser utilizadas não são nem de perto comparaveis em tamanho a essa. São imagens de 50+mpx com muitos MB's.

Já exprimentei carregar uma e até não correu mal(cerca de 1 seg de delay), mas isso sou eu que apesar de não ter grande grafica, tenho um processador fortemente overclockado, que facilmente faz 5 computadores de escola.

Isto não utiliza acelaração grafica pois não?

Vou tratar agora(ou amanhã) disso do POI.

EDIT ADD:

Como poderei apagar os objectos que possam ter sido desenhados no paint() para os voltar a desenhar novamente noutras posições(devido ao zoom e ao pan)?

Mais uma vez obrigado.

Edited by claudiop

When you have nothing to do, try thinking about thinking. mind(){mind();}

Share this post


Link to post
Share on other sites
claudiop

EDIT:

Espero que ninguem tenha gasto a vista a ler o codigo que este post tinha.

Desperdicio de QI total.

Fiz merge da Classe Render, e da PanAndZoom.

Background.java:

public class Background extends JLabel implements ChangeListener  {
   private ImageIcon background;
   private BufferedImage image;
   private double scale;
   public Background(JPanel parent){
       super();
       parent.add(this);
       try {
           image = ImageIO.read(new File("/example/background"));
       } catch (IOException e) {
           e.printStackTrace();
       }
       this.background = new ImageIcon(image);
       this.setIcon(background);
   }
   public void stateChanged(ChangeEvent e) {
       int value = ((JSlider) e.getSource()).getValue();
       this.scale = value / 100.0;
       BufferedImage scaled = getScaledImage(scale);
       this.setIcon(new ImageIcon(scaled));
       this.revalidate();
       this.repaint();//<<------ SOLUÇÂO MILAGROSA
   }
   private BufferedImage getScaledImage(double scale) {
       int w = (int) (scale * image.getWidth());
       int h = (int) (scale * image.getHeight());
       BufferedImage bi = new BufferedImage(w, h, image.getType());
       Graphics2D g2 = bi.createGraphics();
       g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
       AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
       g2.drawRenderedImage(image, at);
       g2.dispose();
       return bi;
   }
   @Override
   public void paintComponent(Graphics g){
       super.paint(g);
       /*
       * Componentes pintados com recurso á escala da imagem de fundo
       */
   }

Edited by Baderous
geshi

When you have nothing to do, try thinking about thinking. mind(){mind();}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.