2009-11-04 16 views
8

पिछले दो दिनों से मैंने को समझने की कोशिश की है कि जावा ग्राफिक्स को कैसे संभालता है, लेकिन बस उस पर दुर्भाग्य से विफल रहा है। मेरी मुख्य समस्या यह समझ रही है कि कैसे और कब पेंट() (या नया पेंट कॉम्पोनेंट())/कॉल किया जाना चाहिए।पेंट()/paintComponent() कभी क्यों नहीं कहा जाता है?

निम्नलिखित कोड में मैंने यह देखने के लिए बनाया कि चीजें कब बनाई जाती हैं, पेंट कॉम्पोनेंट() को कभी भी नहीं कहा जाता है, जब तक कि मैं इसे मैन्युअल रूप से कॉल नहीं करता या JFrame.paintAll()/JFrame.paintComponents() पर कॉल करता हूं।

मैंने पेंट() विधि को पेंट कॉम्पोनेंट() को पेंट करने के लिए नाम दिया है ताकि उम्मीद की जा सके कि इसकी समस्या को ठीक नहीं किया जाएगा (यहां तक ​​कि repaint() पर भी, लेकिन कोई भाग्य नहीं है।

package jpanelpaint; 

import java.awt.*; 
import javax.imageio.*; 
import javax.swing.*; 
import java.io.*; 
import java.util.ArrayList; 

public class ImageLoadTest extends JComponent { 
ArrayList<Image> list; 

public ImageLoadTest() { 
    list = new ArrayList<Image>(); 

    try { //create the images (a deck of 4 cards) 
    for(String name : createImageFileNames(4)){ 
    System.err.println(name); 
    list.add(ImageIO.read(new File(name))); 
    } 
    } catch (IOException e) { } 
} 

    protected void paintComponent(Graphics g) { 
    int yOffset=0; 
    System.err.println("ImageLoadTest.paintComponent()"); 
    for(Image img : list) { 
     g.drawImage(img, 0, yOffset, null); 
     yOffset+=20; 
    } 
    } 

public static void main(String args[]) throws InterruptedException { 
    JFrame frame = new JFrame("Empty JFrame"); 
    frame.setSize(new Dimension(1000, 500)); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    frame.setVisible(true); 

    Thread.sleep(1000); 
    frame.setTitle("Loading images"); 
    ImageLoadTest ilt = new ImageLoadTest(); 
    frame.add(ilt); 
    //update the screen 
    //DOESN'T WORK. only works if I call frame.paintAll(frame.getGraphics()) 
    ilt.repaint(); 
    frame.repaint(); 

    Thread.sleep(1000); 
    frame.setTitle("Setting background"); 
    ilt.setBackground(Color.BLACK); 
    //update the screen - DOESN'T WORK even if I call paintAll .. 
    ilt.repaint(); 
    frame.repaint(); 

      //have to call one of these to get anything to display 
// ilt.paintComponent(frame.getGraphics()); //works 
    frame.paintComponents(frame.getGraphics()); //works 
} 

//PRIVATE HELPER FUNCTIONS 

private String[] createImageFileNames(int count){ 
    String[] fileNames = new String[count]; 
    for(int i=0; i < count; i++) 
    fileNames[i] = "Cards" + File.separator + (i+1) + ".bmp"; 
    return fileNames; 
} 
} 

उत्तर

3

ये मूल कोड है कि यह काम करने के लिए नहीं की वजह से साथ मुख्य समस्या आई थी:

  1. सी नहीं जोड़ने के बाद() ऑपरेशन
  2. घटक के पसंदीदा आकार को सेट करने के बाद मान्य करना।
  3. बुला नहीं super.paintComponent() जब यह अधिभावी
  4. मैं क्रम में JPanel से इनहेरिट करना के लिए यह पेंट करने के लिए की जरूरत है (इस setBackground() काम नहीं फोन किया)। न तो घटक है और न ही JComponent setBackground के लिए पर्याप्त() काम करने के लिए कहते हैं, तब भी जब फिक्सिंग बिंदु 3.

किया करने के बाद से ऊपर था, यह वास्तव में कोई फर्क नहीं था, तो विधि paintComponent या रंग बुला, दोनों काम करने के लिए लग रहा था जब तक मुझे शुरुआत में सुपर कन्स्ट्रक्टर को कॉल करने के लिए याद किया गया।

यह जानकारी @jitter, @tackline, और @camickr द्वारा लिखी गई थी, इतनी बड़ी कुडोस!

पीएस कोई विचार नहीं है कि अगर आपके अपने प्रश्न का उत्तर खराब रूप माना जाता है, लेकिन चूंकि मुझे जो जानकारी चाहिए वह कई उत्तरों से इकट्ठा किया गया था, मैंने सोचा कि सबसे अच्छा तरीका अन्य उत्तरों को ऊपर उठाना और इस तरह की राशि लिखना था।

4

एक प्रमुख मुद्दा यहाँ आप Event Dispatch Thread (EDT) पर अपनी स्विंग घटकों को अद्यतन करने के लिए नहीं कर रहे हैं। निम्नलिखित में अपने मुख्य विधि में सभी कोड लपेटकर का प्रयास करें:

SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      // swing code here...    
     } 
    }); 

इसके अलावा: फ्रेम दिखाई सेट करने से पहले फ्रेम करने के लिए अपने ImageLoadTest जोड़ें। यह कोड के त्वरित कर्सर पढ़ने पर आधारित है - मैं इसे और पढ़ूंगा और देख सकता हूं कि मुझे और क्या मिल सकता है।

संपादित करें:

ऊपर अपने मूल सलाह का पालन करें, और निम्न और अपने paintComponent (तरह देखने के लिए अपने मुख्य विधि को सरल बनाने) कहा जाएगा:

public static void main(String args[]) throws InterruptedException { 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      JFrame frame = new JFrame("Empty JFrame"); 
      frame.setSize(new Dimension(1000, 500)); 
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
      PaintComponentTest ilt = new PaintComponentTest(); 
      frame.add(ilt); 
      frame.setVisible(true); 
      ilt.setBackground(Color.BLACK); 
     } 
    }); 
} 

इसके अलावा मैं पर पढ़ा होगा एनीमेशन करने के लिए टाइमर का उपयोग करना, साथ ही साथ सामान्य स्विंग इवेंट प्रेषण और विभिन्न पेंट विधियों को ओवरराइड करने के लिए/कब।

http://java.sun.com/products/jfc/tsc/articles/painting/

http://java.sun.com/docs/books/tutorial/uiswing/misc/timer.html

http://java.sun.com/docs/books/tutorial/uiswing/concurrency/dispatch.html

+0

धन्यवाद, कोशिश करेंगे। लेकिन क्या मुझे वास्तव में काम करने के लिए अंत में सेटविज़िबल का उपयोग करना चाहिए? इसे जल्दी कॉल करने वाला बिंदु यह देखना था कि मुझे बाद में अतिरिक्त ग्राफिकल तत्व जोड़ने को कैसे संभालना चाहिए। लेकिन पूरी तरह से चलने योग्य चीज़ मेरे लिए नई थी; मैंने नहीं देखा है कि मैंने देखा है कि किसी भी ट्यूटोरियल में (जैसे this one)। – oligofren

+0

[java.awt.EventQueue.'] 'invokeLater' का उपयोग करके यह मेरे लिए काम करता है। –

+1

(हालांकि यह शायद एक बग को कवर कर रहा है। हालांकि 'add'' के लिए एपीआई दस्तावेज़ों में वर्णित 'add' के बाद आपको' पुनः सत्यापित 'करना चाहिए।) –

2

मैं "गंदी अमीर ग्राहक" के अध्यायों की पहली जोड़ी को पढ़ने की सलाह। मैं वर्षों से स्विंग का उपयोग कर रहा था, लेकिन इस पुस्तक को पढ़ने के बाद ही मैंने अंत में पूरी तरह से समझ लिया कि जावा की पेंटिंग तंत्र कैसे काम करता है।

+0

यह एक अच्छी टिप थी। मैं वास्तव में इसे बाद में पढ़ा। शानदार पुस्तक, यद्यपि जीयूआई काम वेब की इस दुनिया में देर से नब्बे के दशक की बात है। – oligofren

11

मूल कोड में पेंट कॉम्पोनेंट() को शामिल नहीं किया गया कारणों में से एक कारण यह है कि घटक का "शून्य आकार" होता है और रिपेंटमेंजर पर्याप्त स्मार्ट है जो कुछ आकार के साथ कुछ कोशिश करने और पेंट करने के लिए पर्याप्त नहीं है।

कोड कामों की पुनरावृत्ति का कारण यह है कि जब आप फ्रेम में घटक जोड़ते हैं और फिर फ्रेम को दृश्यमान लेआउट प्रबंधक को घटक लेआउट के लिए बुलाया जाता है। डिफ़ॉल्ट रूप से एक फ्रेम BorderLayout का उपयोग करता है और डिफ़ॉल्ट रूप से एक घटक BorderLayout के केंद्र में जोड़ा जाता है जो घटक के लिए उपलब्ध सभी स्थान देता है, इसलिए इसे चित्रित किया जाता है।

हालांकि, आप फ्लोलाउट होने के लिए सामग्री फलक के लेआउट प्रबंधक को बदलते हैं, फिर भी आपको कोई समस्या होगी क्योंकि फ़्लोलाउट घटक के पसंदीदा आकार का सम्मान करता है जो शून्य है।

तो आपको वास्तव में क्या करना है, यह आपके घटक को एक पसंदीदा आकार असाइन करना है ताकि लेआउट प्रबंधक अपना काम कर सकें।

4

बनाने के लिए टॉम Hawtin - tackline खुश।मैं एक बार दुबारा लिखा फिर

कई चीज़ें हैं जिन्हें मैं बदल ( //new टिप्पणी के साथ लाइनों की जांच कर रहे हैं)

दुबारा लिखा यह पूरी तरह से

  • एक साफ नए घटक फ़ाइल (ImageLoadTest.java) में विभाजित है और एक यह (Tester.java)

मूल पोस्टर कोड पर सुधार का परीक्षण करने के लिए फ़ाइल

+०१२३५१६४१० निर्माता में घटक के setPreferredSize() करने के लिए कॉल: ImageLoadTest निर्माता ( super())
  • प्रदान की दूसरी निर्माता में माता पिता की
    • कॉल निर्माता छवियों की सूची जो घटक
    • महत्वपूर्ण प्रदर्शित करना चाहिए निर्धारित करने के लिए। यदि आकार सेट नहीं किया गया है तो निश्चित रूप से स्विंग आपके घटक को पेंट नहीं करेगा। पसंदीदा आकार अधिकतम पर आधारित है। सभी छवियों की और सभी छवि ऊंचाइयों के योग पर चौड़ाई
    • ओवरराइड paintComponent()
    • में super.paintComponent(g) को

    • कॉल बदल paintComponent स्वचालित रूप से चित्रों की ऊंचाई तैयार किया जा रहा

    • जीयूआई EDT

      पर
    • किया आरंभीकरण पर yOffset आधार पर छवियों को लोड करने और लोड करने के लिए sleep() का उपयोग करने के आधार पर मूल कोड के रूप में लंबे समय तक SwingWorker का उपयोग किया जा सकता है
    • worker तब प्रतीक्षा करता है जब नया शीर्षक सेट करता है और फिर
    • workerdone() में JFrame में घटक को जोड़ता है और इसे प्रदर्शित करता है। JFrame एपीआई में वर्णित JFrame की सामग्री फलक में घटक जोड़ा गया। और जैसा कि पर कॉल करने के बाद JFrame पर JFrame पर जावडोक में वर्णित validate() पर आवश्यक कॉल किया गया था, क्योंकि JFrame एक पहले से दिखाई देने वाला कंटेनर है जो बच्चों को बदलता है।

    javdoc प्रशस्ति पत्र से validate()

    सत्यापित करें विधि फिर से अपने उप-घटक बाहर बिछाने के लिए एक कंटेनर पैदा करने के लिए प्रयोग किया जाता है। यह कंटेनर के सबकंपोनेंट संशोधित किए जाने चाहिए ( कंटेनर से जोड़ा या हटा दिया गया है, या लेआउट से संबंधित जानकारी बदली गई है) कंटेनर प्रदर्शित होने के बाद।

    • दूसरे कार्यकर्ता बस इंतजार कर फिर काला
    • ImageLoadTest के लिए baseclass के रूप में इस्तेमाल किया JPanelsetBackground() जो मैं JComponent के साथ काम करने नहीं मिल सका ठीक करने के लिए पृष्ठभूमि रंग सेट कुछ और है।
    तो अपने मुख्य समस्याओं में जहां कि आप घटक के वांछित आकार सेट नहीं किया और कहा कि आप पहले से ही दिखाई दे रहा कंटेनर के लिए कुछ जोड़ने के बाद JFrame पर validate() फोन नहीं किया

    यह काम करना चाहिए

    jpanelpaint/ImageLoadTest.java

    package jpanelpaint; 
    
    import java.awt.Dimension; 
    import java.awt.Graphics; 
    import java.awt.Image; 
    import javax.swing.JPanel; 
    import java.util.List; 
    
    public class ImageLoadTest extends JPanel { 
        private List<Image> list; 
    
        public ImageLoadTest() { 
        super(); 
        } 
    
        public ImageLoadTest(List<Image> list) { 
        this(); 
        this.list = list; 
        int height = 0; 
        int width = 0; 
        for (Image img : list) { 
         height += img.getHeight(this); 
         width = img.getWidth(this) > width ? img.getWidth(this) : width; 
         setPreferredSize(new Dimension(width, height)); 
        } 
        } 
    
        @Override 
        protected void paintComponent(Graphics g) { 
        int yOffset=0; 
        super.paintComponent(g); 
        System.err.println("ImageLoadTest.paintComponent()"); 
        for(Image img : list) { 
         g.drawImage(img, 0, yOffset, null); 
         yOffset+=img.getHeight(this); 
        } 
        } 
    } 
    

    Tester.java

    import java.awt.Dimension; 
    import java.awt.Color; 
    import java.awt.Image; 
    import java.io.File; 
    import java.io.IOException; 
    import javax.imageio.ImageIO; 
    import javax.swing.JFrame; 
    import javax.swing.SwingWorker; 
    import javax.swing.SwingUtilities; 
    import java.util.List; 
    import java.util.ArrayList; 
    import java.util.concurrent.ExecutionException; 
    import jpanelpaint.ImageLoadTest; 
    
    public class Tester { 
    
        private JFrame frame; 
        private ImageLoadTest ilt; 
        private final int NUMBEROFFILES = 4; 
        private List<Image> list; 
    
        //will load the images 
        SwingWorker worker = new SwingWorker<List<Image>, Void>() { 
        @Override 
        public List<Image> doInBackground() throws InterruptedException { 
         //sleep at start so user is able to see empty jframe 
         Thread.sleep(1000); 
         //let Event-Dispatch-Thread (EDT) handle this 
         SwingUtilities.invokeLater(new Runnable() { 
         public void run() { 
          frame.setTitle("Loading images"); 
         } 
         }); 
         //sleep again so user is able to see loading has started 
         Thread.sleep(1000); 
         //loads the images and returns list<image> 
         return loadImages(); 
        } 
    
        @Override 
        public void done() { 
         //this is run on the EDT anyway 
         try { 
         //get result from doInBackground 
         list = get(); 
         frame.setTitle("Done loading images"); 
         ilt = new ImageLoadTest(list); 
         frame.getContentPane().add(ilt); 
         frame.getContentPane().validate(); 
         //start second worker of background stuff 
         worker2.execute(); 
         } catch (InterruptedException ignore) {} 
         catch (ExecutionException e) { 
         String why = null; 
         Throwable cause = e.getCause(); 
         if (cause != null) { 
          why = cause.getMessage(); 
         } else { 
          why = e.getMessage(); 
         } 
         System.err.println("Error retrieving file: " + why); 
         } 
        } 
        }; 
    
        //just delay a little then set background 
        SwingWorker worker2 = new SwingWorker<Object, Void>() { 
        @Override 
        public List<Image> doInBackground() throws InterruptedException { 
         Thread.sleep(1000); 
         SwingUtilities.invokeLater(new Runnable() { 
         public void run() { 
          frame.setTitle("Setting background"); 
         } 
         }); 
         Thread.sleep(1000); 
         return null; 
        } 
    
        @Override 
        public void done() { 
         ilt.setBackground(Color.BLACK); 
         frame.setTitle("Done!"); 
        } 
        }; 
    
        public static void main(String args[]) { 
        new Tester(); 
        } 
    
        public Tester() { 
        //setupGUI 
        SwingUtilities.invokeLater(new Runnable() { 
         public void run() { 
         frame = new JFrame("Empty JFrame"); 
         frame.setSize(new Dimension(1000, 500)); 
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
         frame.setVisible(true); 
         } 
        }); 
    
        //start the swingworker which loads the images 
        worker.execute(); 
        } 
    
        //create image names 
        private String[] createImageFileNames(int count){ 
        String[] fileNames = new String[count]; 
        for(int i=0; i < count; i++) 
         fileNames[i] = "Cards" + File.separator + (i+1) + ".bmp"; 
        return fileNames; 
        } 
    
        //load images 
        private List<Image> loadImages() { 
        List<Image> tmpA = new ArrayList<Image>(); 
        try { 
         for(String name : createImageFileNames(NUMBEROFFILES)){ 
         System.err.println(name); 
         tmpA.add(ImageIO.read(new File(name))); 
         } 
        } catch (IOException e) { } 
    
        return tmpA; 
        } 
    } 
    
  • +0

    आप अभी भी ईडीटी से स्विंग सामान कर रहे हैं! –

    +0

    स्पष्ट इंगित करने के लिए धन्यवाद।8 | मुझे ऊपर उठाने के बजाय क्योंकि मैंने प्रश्न पोस्टर की वास्तविक समस्याओं को हल किया है (छवियां + पृष्ठभूमि नहीं दिख रही है) आप मुझे किसी अन्य पोस्टर के लिए पहले ही समझाए गए हैं। मैंने सोचा कि कम से कम ओलिगोफेरेन अपने समाधान में खुद को – jitter

    +0

    वाह कर सकता है, वाह, जिटर, यह केवल सबूत-अवधारणा कोड को ठीक करने के लिए बहुत काम है! थोड़ा अधिक, शायद, लेकिन एक बड़ा धन्यवाद, वैसे भी। मैंने मूल कोड में मुख्य मुद्दों को ठीक करने के लिए आपके कोड का उपयोग किया: 1) किसी ऐड() ऑपरेशन 2 के बाद मान्य() को कॉल नहीं करना) घटक के पसंदीदा आकार को सेट नहीं करना। 3) super.paintComponent() को ओवरराइड करते समय कॉल नहीं करते (यह सेटबैकग्राउंड() कॉल काम नहीं करता है। ऐसा करने के बाद, सबकुछ इरादे से काम करता है। इसे देखने के लिए मूल पोस्ट को संपादित करना। – oligofren

    संबंधित मुद्दे