Graphics2D Dlaczego źle wyświetla

0

Program ma działać a la paint. Prawie działa. Nie rozumiem czemu dorysowywuje w lewym górnym rogu panelu p2 ikonki naciśnięte. Proszę więc o pomoc. Jako, że dopiero zaczynam przygodę z java program zapewne jest jak to mówią nieelegancki.
Z góry dziękuję za wszelkie podpowiedzi.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.HeadlessException;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;


public class Doda extends JFrame implements WindowListener, ActionListener,
		ItemListener, KeyListener, MouseListener,MouseMotionListener, AdjustmentListener {

	static Doda a;
	JToolBar bar;
	JPanel p1, p2;
	Point startPoint, endPoint, point1, point2;
	JButton b1, b2, b3, b4, b5, B;
	boolean czy1=false, czy2=false, czy3=false, czy4=false, czy5=false;
	Color color, col;
	
	public Doda() throws HeadlessException {
		// TODO Auto-generated constructor stub
		setSize(1000,700);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        p1= new JPanel();
        p2= new MyPanel();
        add(BorderLayout.NORTH, p1);
        p1.setSize(1000, 100);
        add(BorderLayout.CENTER, p2);
        bar = new JToolBar();
        p1. add (bar);
        p1.setBackground(Color.GRAY);
       
        b1 = new JButton(new ImageIcon("im.JPG"));
        bar.add(b1);
        b1.setToolTipText("linia");
        b1.addActionListener(this);
        b2 = new JButton(new ImageIcon("im.JPG"));
        bar.add(b2);
        b2.setToolTipText("linia");
        b2.addActionListener(this);
        b3 = new JButton(new ImageIcon("im.JPG"));
        bar.add(b3);
        b3.setToolTipText("linia");
        b3.addActionListener(this);
        b4 = new JButton(new ImageIcon("im.JPG"));
        bar.add(b4);
        b4.setToolTipText("linia");
        b4.addActionListener(this);
        b5 = new JButton(new ImageIcon("im.JPG"));
        bar.add(b5);
        b5.setToolTipText("linia");
        b5.addActionListener(this);
        
        B=new JButton("KOLOR");
        //Anonimowa klasa wewnetrzna
		B.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				col=color;
				color=JColorChooser.showDialog(null, "wybierz kolor", color);		
			if(color==null)color=col;
			}
		});      
		p1.add(B);
		
        addMouseListener(this);
	
	}

	public Doda(GraphicsConfiguration arg0) {
		super(arg0);
		// TODO Auto-generated constructor stub
	}

	public Doda(String arg0) throws HeadlessException {
		super(arg0);
		// TODO Auto-generated constructor stub
	}

	public Doda(String arg0, GraphicsConfiguration arg1) {
		super(arg0, arg1);
		// TODO Auto-generated constructor stub
	}

	@Override
	public void adjustmentValueChanged(AdjustmentEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseClicked(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub

		startPoint = new Point(e.getPoint());

	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub

		endPoint = new Point(e.getPoint());
		p2.repaint();
		
	}

	@Override
	public void keyPressed(KeyEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void itemStateChanged(ItemEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if(e.getSource() == b1){
			czy1=true;
			czy2=false;
			czy3=false;
			czy4=false;
			czy5=false;
			}
		if(e.getSource() == b2){
			czy1=false;
			czy2=true;
			czy3=false;
			czy4=false;
			czy5=false;
		}
		if(e.getSource() == b3){
			czy1=false;
			czy2=false;
			czy3=true;
			czy4=false;
			czy5=false;
		}
		if(e.getSource() == b4){
			czy1=false;
			czy2=false;
			czy3=false;
			czy4=true;
			czy5=false;
		}
		if(e.getSource() == b5){
			czy1=false;
			czy2=false;
			czy3=false;
			czy4=false;
			czy5=true;
		}
	}

	@Override
	public void windowActivated(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowClosed(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowClosing(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowDeactivated(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowDeiconified(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowIconified(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowOpened(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		a = new Doda();
	}

	public void mouseDragged(MouseEvent e)
	{

	}

	@Override
	public void mouseMoved(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	
	 public class MyPanel extends JPanel {  
		     public MyPanel() {  
		     }  
		   
		 	public void paint(Graphics g)
			{     
				
			      Graphics2D g2 = (Graphics2D)g;

				g2.setColor(color);
				startPoint.y=startPoint.y-70;
				endPoint.y=endPoint.y-70;
				if (czy1){
				g2.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
				
				}
				
				point1 = new Point();
				point2 = new Point();
				if(startPoint.x<endPoint.x){
					point1.x=startPoint.x;
					point2.x=endPoint.x;
				}
				if(startPoint.y<endPoint.y){
					point1.y=startPoint.y;
					point2.y=endPoint.y;
				}
				if(startPoint.x>endPoint.x){
					point2.x=startPoint.x;
					point1.x=endPoint.x;
				}
				if(startPoint.y>endPoint.y){
					point2.y=startPoint.y;
					point1.y=endPoint.y;
				}
				if (czy2){
		    	g2.drawRect(point1.x, point1.y, point2.x-point1.x, point2.y-point1.y);
		    	
				}
				if (czy3){
		    	g2.drawOval(point1.x, point1.y, point2.x-point1.x, point2.y-point1.y); 
		    	
				}
				if (czy4){
		    	g2.fillRect(point1.x, point1.y, point2.x-point1.x, point2.y-point1.y);
		    	
				}
				if (czy5){
		    	g2.fillOval(point1.x, point1.y, point2.x-point1.x, point2.y-point1.y); 
		    	
				}
		    	//g.setFont(Font f);
		    	//g.setString("Tekst", int x, int y);


			}
		 
			
		     }  
		 }  
0

Zmień "public void paint(Graphics g)" na "public void paintComponent(Graphics g)" oraz dodaj w tej metodzie w pierwszej linii "super.paintComponent(g)".

0

To faktycznie usuwa problem tych niechcianych ikonek. Ale co zrobić, żeby za każdym razem nie odświeżało JPanel p2? Tzn. żeby było widać wcześniej narysowane kształty

0

Możesz wykonać jedną z dwóch rzeczy:

  1. W metodzie paintComponent rysować za każdym razem wszystkie kształty.
  2. Rysować na zewnętrzym obiekcie Graphics2D, a w metodzie paintComponent jedynie wyświetlać zawartość tamtej grafiki. Można to zrobić zmieniając paintComponent, aby zazierała jedynie linię super.paintComponent(zewnetrznaGrafika) (metoda paintComponent będzie wtedy ignorować obiekt Graphics przekazany w argumencie).
0

Chyba rozumiem, ale nie umiem tego zrealizować. Przecież do obiektu zewnetrznaGrafika nie mogę wpisać tych wszystkich poleceń, które mają rysować.

0

Możesz. Wersja najprostsza: W pamięci Tworzysz sobie obrazek, który na którym będziesz obrabiał różne zmiany - możesz go sobie wczytać z pliku tak jak każdy program graficzny. Następnie obrazek ten odmalowujesz w paint lub dowolnej jego wersji na ekranie okna (cały przeskalowany, lub tylko część). Kiedy będziesz używał jakiegoś narzędzia graficznego do mazania po oknie, to tak naprawdę nie obchodzi Cię odmalowywanie tego na ekranie, ale zapisywanie ruchów pędzla czy co tam się użyje i przeniesieniu tych ruchów na właściwy obrazek w pamięci, którzy rzeczywiście zostanie zmieniony. Ten sam obrazek jest przez paint wyświetlany (jakieś drawImage) na ekranie i już wtedy widać zmiany, które zostały w nim zrobione. To wersja najprymitywniejsza. Inna jest taka, że zapisujesz ruchy narzędziami i po prostu kolejno je odrysowujesz na widoku obrazka, a więc w każdej chwili można zrobić perfekcyjne undo (przynajmniej aż do czasu trwałego nałożenia zmian na obrazek - np. podczas zapisu do pliku). W ten sam sposób można sobie realizować warstwy, mieszanie z grafiką wektorową i różne cuda na kiju. Co tylko przyjdzie do głowy. Po prostu wystarczy wiedzieć, że paint służy jedynie do wybiórczego przekazania na ekran tego co dzieje się gdzieś w pamięci. Na przykład w przypadku warstw lub orientacji obiektowej w metodzie odrysowującej ekran będzie jedynie prosta pętla odrysowująca kolejno te warstwy lub obiekty na ekran.

0
Olamagato napisał(a)

Inna jest taka, że zapisujesz ruchy narzędziami i po prostu kolejno je odrysowujesz na widoku obrazka, a więc w każdej chwili można zrobić perfekcyjne undo (przynajmniej aż do czasu trwałego nałożenia zmian na obrazek - np. podczas zapisu do pliku). W ten sam sposób można sobie realizować warstwy, mieszanie z grafiką wektorową i różne cuda na kiju. Co tylko przyjdzie do głowy. Po prostu wystarczy wiedzieć, że paint służy jedynie do wybiórczego przekazania na ekran tego co dzieje się gdzieś w pamięci. Na przykład w przypadku warstw lub orientacji obiektowej w metodzie odrysowującej ekran będzie jedynie prosta pętla odrysowująca kolejno te warstwy lub obiekty na ekran.

Próbuje coś wykombinować żeby to zrealizować, ale nic nie wychodzi. Nie wiem jak zapisywać te ruchy narzędziami, już nie mówiąc o ich odrysowaniu. Jakby ktoś chociaż hasłami rzucił nazwy metod jakie trzeba by tu użyć to wtedy znajdę tutoriale konkretne.

0

Proszę bardzo. Ruch narzędziem, to nic innego jak zapisywanie kolejnych położeń kursora myszki - na przykład wtedy kiedy jest przyciśnięty lewy button. Współrzędne te dostajesz w relacji do lewego górnego rogu wyświetlanego komponentu - na przykład JPanel i wtedy musisz sobie je przełożyć na współrzędne względem lewego rogu obrazka (lub jego części) - jest to szczególnie ważne jeżeli wyświetlasz obrazek z jakimś powiększeniem i albo jest on mniejszy od panelu, albo większy i widać na nim tylko jego część. Tak uzyskaną współrzędną kursora zapisujesz po prostu do jakiejś listy współrzędnych - może to być np. ArrayList<Point>. Dodajesz te współrzędne tak długo jak długo nie nadejdzie zdarzenie puszczenia LPM. Uzyskana lista współrzędnych, to właśnie jeden ruch myszą względem obrazka w pamięci (drag). Jeżeli wykonasz w pętli for/while ciąg wywołań drawLine z kolejnymi współrzędnymi z tej listy bieżącym "rysikiem", to na tym obrazku namalujesz kreski dokładnie odpowiadające temu co zrobiłeś ręką poruszając myszą na ekranie. Wtedy możesz ustawić tak "pomazany" obrazek jako do odrysowania, a wtedy paint odświeżając obraz pokaże zmodyfikowany obrazek lub jego wyświetlaną część.
Wszystko to zrobi się w ułamku sekundy, więc dla Ciebie będzie to wyglądać tak jakbyś rysował bezpośrednio po ekranie o ile na ekranie w czasie przesuwania myszą też rysowałeś linie z poprzedniego punktu do bieżącego. Efekt byłby taki, że w czasie naciskania myszą mógłbyś widzieć ciągłą linię w kolorze czarnym, a po puszczeniu LPM mogłaby stać się natychmiast np. przerywana i różowa.
Inną, częściej używaną odmianą, mogłoby być odrysowywanie na ekranie właściwym narzędziem co jedną odczytaną współrzędną, aby widzieć to co rysujesz, ale nie mazanie tym narzędziem po obrazku w pamięci lecz zapisanie oprócz listy ruchów myszą również niezbędne parametry tego narzędzia - typ, kolor, szerokość pędzla itp. Dzięki temu w każdej chwili będziesz w stanie powtórzyć te ruchy na obrazku w pamięci - i to wielokrotnie (np. użyłeś 8 narzędzi po sobie w różnych miejscach). W ten sposób masz pełną kontrolę nad edycją obrazu, z nieograniczonym undo i niezależnością od skali wyświetlania go na ekranie (w okienku lub fullscreenie).
Oczywiście wszystko dzieje się w czasie rzeczywistym, więc wydaje Ci się, że naprawdę rysujesz po ekranie.
Tak mniej więcej działają wszystkie profesjonalne edytory graficzne - bitmapowe (coraz częściej) i wektorowe (wszystkie).

Dzięki takiemu podejściu możesz zapisywać jako plik wyjściowy oryginalny obrazek i jedynie listy ruchów narzędzi, co oznacza, że po załadowaniu takiego pliku znowu masz pełne undo tak jakbyś nigdy nie przerywał swojej pracy nad obrazkiem. Tak zapisuje właśnie Photoshop w swoim pliku roboczym (i inne konkurencyjne programy też).

1 użytkowników online, w tym zalogowanych: 0, gości: 1