2014-01-27 2 views
0

Я работаю над простой панелью рисования на Java, и у меня есть несколько инструментов, с которыми пользователь может работать: ручку и ластик. Но JComboBox, используемый для выбора инструмента, не появляется, даже если он добавлен. Я слышал, что пользовательская краска будет скрывать любые JComponents. Если это так, как я могу заставить JComboBox всегда быть наверху?Почему мой JComboBox не рисует мои рисунки?

Изображение окна:

picture of bugged window

Вот мой код:

import java.awt.Color; 
import java.awt.FlowLayout; 
import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionListener; 
import java.util.ArrayList; 

import javax.swing.JComboBox; 
import javax.swing.JFrame; 


public class DrawFrame extends JFrame implements MouseMotionListener, Runnable { 
    private static final long serialVersionUID = 1L; 

    private Image dbi; 
    private Graphics dbg; 

    ArrayList<Integer> px = new ArrayList<Integer>(); 
    ArrayList<Integer> py = new ArrayList<Integer>(); 

    int mx; 
    int my; 

    @SuppressWarnings("rawtypes") 
    JComboBox tool = new JComboBox(); 

    @SuppressWarnings("unchecked") 
    public DrawFrame() { 

     setSize(480, 480); 
     setTitle("ScratchPad _14"); 
     setLayout(new FlowLayout()); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setResizable(false); 
     setBackground(Color.WHITE); 
     setOpacity(1); 

     tool.addItem("Pen"); 
     tool.addItem("Eraser"); 

     tool.setEnabled(true); 

     add(tool); 

     setVisible(true); 

     addMouseMotionListener(this); 

    } 

    /*@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 arg0) { 
     // TODO Auto-generated method stub 

    } 

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

    }*/ 

    public static void main(String[] args) { 
     // TODO Auto-generated method stub 

     DrawFrame df = new DrawFrame(); 
     Thread t = new Thread(df); 

     t.start(); 

    } 

    public void paint(Graphics g) { 

     dbi = createImage(getWidth(), getHeight()); 
     dbg = dbi.getGraphics(); 
     draw(dbg); 
     g.drawImage(dbi, 0, 0, null); 

    } 

    private void draw(Graphics g) { 
     // TODO Auto-generated method stub 

     super.paint(g); 

     g.setColor(getBackground()); 
     g.fillRect(0, 0, getWidth(), getHeight()); 

     g.setColor(Color.BLACK); 
     for (int i = 0; i < px.size(); i++) { 

      g.fillOval(px.get(i), py.get(i), 3, 3); 

     } 

     g.setColor(Color.BLUE); 
     g.drawString("(" + mx + ", " + my + ")", mx + 10, my - 5); 

     repaint(); 

    } 

    @Override 
    public void run() { 
     // TODO Auto-generated method stub 

     while(true) { 

      try { 
       Thread.sleep(5); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

     } 

    } 

    @Override 
    public void mouseDragged(MouseEvent m) { 
     // TODO Auto-generated method stub 

     int x = m.getX(); 
     int y = m.getY(); 

     mx = x; 
     my = y; 

     px.add(x); 
     py.add(y); 

    } 

    @Override 
    public void mouseMoved(MouseEvent m) { 
     // TODO Auto-generated method stub 

     int x = m.getX(); 
     int y = m.getY(); 

     mx = x; 
     my = y; 

    } 

} 

Заранее спасибо!

ответ

2

Потому что вы назвали super.paint, который рисует дочерние компоненты, среди прочего

super.paint(g); 

Затем вы заполнили весь кадр с цветом фона, используя ...

g.setColor(getBackground()); 
g.fillRect(0, 0, getWidth(), getHeight()); 

Стирание, который был окрашен до этого ...

Вам следует избегать переопределения paint контейнеров верхнего уровня, таких как JFrame, помимо того факта, что вы будете рисовать под рамными украшениями и не буферизироваться с двойным буфером, эти контейнеры фактически состоят из ряда составных компонентов, которые производят конечный результат.

Вместо этого создайте пользовательский компонент, простирающийся от JPanel, и переопределите его метод paintComponent. Поместите свою обычную картину здесь.

Добавьте поле со списком и настраиваемую панель краски на раме отдельно

Кроме того, ничего из любого метода рисования, который может генерировать событие перекрашивать (как вызов repaint) не звонить, это создаст бесконечный цикл который будет быстро потреблять ваш процессор

Посмотрите на Performing Custom Painting для более подробной информации

+0

Удаление 'super.paint (g)' не делает ничего видимого. И кадр двойной буферизации. –

+0

Никогда не прекращайте вызов super.paint, это не проблема. Проблема заключается в том, что 'super.paint', красит дочерние компоненты, но потом вы нарисовываете их, и да, вы дважды буферизировали фрейм, но угадайте, что JComponent имеет двойной буфер по умолчанию, избавляя вас от необходимости делать это самостоятельно , JFrame состоит из панели JRootPane, JLayeredPane, панели контента и стекла, и вы только что нарисовали ее. Если вы хотите исправить эту проблему, отделите свою собственную покраску и компоненты. – MadProgrammer

+0

В eclipse, а не вручную двойная буферизация заставляет рисунок мигать со слишком большим количеством элементов на экране. –

0

В общем, один должен обычно не переопределить метод краски JFrame. Вместо этого вы должны расширить JPanel и нарисовать в переопределенном методе paintComponent.

class PaintPanel extends JPanel 
{ 
    public PaintPanel() 
    { 
     setOpaque(false); 
    } 

    @Override 
    protected void paintComponent(Graphics g) 
    { 
     // Paint what you have been painting 
     // in your "draw" method ... 
     ... 
     super.paintComponent(g); 
    } 
} 

Обычно super.paintComponent(g) вызов должен быть первый вызов такой перегруженной метод, но так как вы хотите, чтобы сделать ComboBox выше всего, что вы рисуете по своему усмотрению, он должен быть последним.

Дополнительные вопросы:

  • Что это Нить для?
  • Почему вы делаете ручную двойную буферизацию?
  • Если вы хотите ручной двойной буферизации, вы не должны повторно создать образ в каждой краски вызова

НЕМНОГО очищены, не «хороший» пока нет, но ...таким образом, который по-прежнему напоминает исходную программу, по крайней мере:

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.GridLayout; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionListener; 
import java.util.ArrayList; 

import javax.swing.JComboBox; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 


public class DrawFrame extends JFrame implements MouseMotionListener { 
    private static final long serialVersionUID = 1L; 

    ArrayList<Integer> px = new ArrayList<Integer>(); 
    ArrayList<Integer> py = new ArrayList<Integer>(); 

    int mx; 
    int my; 

    @SuppressWarnings("rawtypes") 
    JComboBox tool = new JComboBox(); 

    @SuppressWarnings("unchecked") 
    public DrawFrame() { 

     setSize(480, 480); 
     setTitle("ScratchPad _14"); 
     setLayout(new GridLayout(1,1)); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setResizable(false); 
     setBackground(Color.WHITE); 
     setOpacity(1); 

     tool.addItem("Pen"); 
     tool.addItem("Eraser"); 

     tool.setEnabled(true); 

     JPanel paintPanel = new PaintPanel(); 
     paintPanel.add(tool); 
     add(paintPanel); 

     setVisible(true); 

     paintPanel.addMouseMotionListener(this); 

    } 
    public static void main(String[] args) { 
     DrawFrame df = new DrawFrame(); 
    } 

    class PaintPanel extends JPanel 
    { 
     public PaintPanel() 
     { 
      setOpaque(false); 
     } 

     @Override 
     protected void paintComponent(Graphics g) 
     { 
      g.setColor(getBackground()); 
      g.fillRect(0, 0, getWidth(), getHeight()); 

      g.setColor(Color.BLACK); 
      for (int i = 0; i < px.size(); i++) { 
       g.fillOval(px.get(i), py.get(i), 3, 3); 
      } 
      g.setColor(Color.BLUE); 
      g.drawString("(" + mx + ", " + my + ")", mx + 10, my - 5); 
      super.paintComponent(g); 
     } 
    } 

    @Override 
    public void mouseDragged(MouseEvent m) { 
     int x = m.getX(); 
     int y = m.getY(); 

     mx = x; 
     my = y; 

     px.add(x); 
     py.add(y); 

     repaint(); 
    } 

    @Override 
    public void mouseMoved(MouseEvent m) { 
     int x = m.getX(); 
     int y = m.getY(); 

     mx = x; 
     my = y; 

    } 

} 
+0

Нить и двойная буферизация препятствуют тому, чтобы рамка не позволяла настраиваемым нарисованным деталям на экране мигать между кадрами. –

+0

Вызывает ли очищенный код мерцание? Компоненты Swing по умолчанию имеют двойной буфер, но переопределение «краски» JFrame уничтожает все, конечно .... – Marco13

+0

Так как я сделал именно это, вероятно, это был @Galen Nare (оригинальный плакат) – Marco13

0

Рисунок не должен перерисовываться. Я сделал это в mouseDragged с задержкой 50 мс. Затем двойная буферизация по умолчанию, поэтому вы не собираете все изменения сначала на изображении. Стирание сделано для одного тоже.

Так код становится:

@Override 
public void paint(Graphics g) { 
    super.paint(g); 
    g.setColor(Color.BLACK); 
    for (int i = 0; i < px.size(); i++) { 
     g.fillOval(px.get(i), py.get(i), 3, 3); 
    } 

    g.setColor(Color.BLUE); 
    g.drawString("(" + mx + ", " + my + ")", mx + 10, my - 5); 
} 

@Override 
public void mouseDragged(MouseEvent m) { 
    ... 
    repaint(50L); 
} 

Обычно один вводит JPanel для рисования, который имеет paintComponent переопределить.

+0

Не вызывая перерисовку, она пропускает кадры. –

+0

@GalenNare затем добавить перерисовку в mouseMoved. Идея состоит в том, что если нет изменений для отображения, не вызывайте перерисовку. Пожалуйста, проверьте в диспетчере задач использование ЦП в обоих случаях. –

Смежные вопросы