سؤال

لمدة يومين آخرين حاولت تفهم كيف تقود جافا الرسومات، لكنها فشلت بشكل كبير في ذلك. مشكلتي الرئيسية هي فهم بالضبط كيف وعندما يتم استدعاء الطلاء (أو الطلاء) () الأحدث ()).

في التعليمات البرمجية التالية التي أدخلتها لمعرفة متى يتم إنشاء الأمور، لا يتم استدعاء الطلاء () PaintComponent () أبدا، إلا إذا قمت بإضافة مكالمة يدويا إليها بنفسي أو استدعاء JFrame.Paintall () / JFrame.PaintClents ().

لقد قمت بإعادة تسمية طريقة الطلاء () ل PaintComponent () على أمل أن إصلاح مشكلتي مطلقا مطلقا (حتى في إعادة رسم ())، ولكن لا حظ.

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;
 }
}
هل كانت مفيدة؟

المحلول 4

كانت هذه هي المشاكل الرئيسية مع التعليمات البرمجية الأصلية التي تسببت في عدم العمل:

  1. عدم الاتصال بالتحقق من صحة () بعد عملية الإضافة ()
  2. عدم تحديد الحجم المفضل للمكون.
  3. عدم الاتصال Super.PaintComponent () عند تجاوزه (هذا جعل STATBABRAURD () مكالمة لا تعمل)
  4. كنت بحاجة إلى الوراثة من JPanel حتى يتم رسمها. لم يكن أي من المكون أو jcomponent كافية للدعوة إلى العمل () للعمل، حتى عند إصلاح النقطة 3.

بعد أن فعلت ما سبق، فإنه لا يهم حقا إذا استدعيت الطريقة الطلاء أو الطلاء، يبدو أن كلاهما يعمل طالما أنني تذكرت أن أتذكر منشئ السوبر في البداية.

تم تجميع هذه المعلومات من TJitter ،Tackline، و camickr كتب، كودوس كبيرة جدا!

PS لا توجد فكرة إذا كانت الإجابة على سؤالك الخاص تعتبر شكل سيء، ولكن نظرا لأن المعلومات التي احتاجتها تم تجميعها من عدة إجابات، فقد اعتقدت أن أفضل طريقة كانت ترتفع الإجابات الأخرى وكتابة مجموع مثل هذا.

نصائح أخرى

أحد الأسباب التي لا يتم الاحتجاج بها PaintCompOrconent () في التعليمات البرمجية الأصلية لأن المكون يحتوي على "حجم صفر" وتم إعادة التسمية ذكية بما يكفي لعدم محاولة ورسم شيء بدون حجم.

السبب في أن إعادة ترتيب الأشكال يعمل هو عند إضافة المكون إلى الإطار، ثم اجعل الإطار مرئيا، يتم استدعاء مدير التخطيط لتخطيط المكون. بشكل افتراضي، يستخدم إطار Borderlayout وإعداد مكون افتراضي يتم إضافة مكون إلى مركز Borderlayout الذي يحدث إعطاء جميع المساحة المتاحة للمكون حتى يتم رسمها.

ومع ذلك، يمكنك تغيير Manager Layout من جزء المحتوى لتكون أداة تدفقية، فستظل مشكلة لأن FlowLayout يحترم الحجم المفضل للمكون الذي هو صفر.

إذن ما تحتاجه حقا إلى القيام به هو تعيين حجم مفضل لك مكونك حتى يمكن لمديري التخطيط القيام بعملهم.

قضية رئيسية واحدة هنا هي أنك لا تقوم بتحديث مكونات التأرجح على الحدث إرسال الموضوع (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.

ليصنع توم حواتين - سعيدة. أعيد كتابة مرة أخرى

هناك العديد من الأشياء التي تغيرت (تحقق من الخطوط مع //new تعليق)

إعادة كتابة ذلك تماما

  • انقسام إلى ملف مكون جديد نظيف (ImageLoadTest.java) وملف لاختباره (Tester.java)

تحسينات على رمز الملصقات الأصلية

  • استدعاء منشئ الوالد في ImageLoadTest البناء (super())
  • قدمت المنشئ الثاني لتعيين قائمة الصور التي يجب أن يعرضها المكون
  • هام: اتصل setPreferredSize() من المكون في المنشئ. إذا لم يكن الحجم لم يحدد التأرجح بالطبع لن يرسم مكونك. يعتمد الحجم المفضل على ماكس. عرض جميع الصور وعلى مجموع جميع مرتفعات الصورة
  • دعوة ل super.paintComponent(g) في تجاوز paintComponent()
  • تغير paintComponent إلى قاعدة تلقائيا yOffset على ارتفاع الصور التي يتم رسمها

  • جوي تهيئة القيام به على EDT

  • كصنونة أصلية تستند إلى استخدام sleep() لتوضيح تحميل وتحميل الصور قد يستغرق وقتا طويلا SwingWorkerيتم استخدام
  • worker ينتظر ثم يحدد عنوان جديد ثم تحميل الصور
  • عند الانتهاء من worker في done() وأخيرا يضيف المكون إلى JFrame ويعرضها. مكون إضافته على جزء المحتوى JFrame كما هو موضح في JFrame. API. وكما هو موضح في Javadoc جعل دعوة ضرورية ل validate() تشغيل JFrame بعد الاتصال add(), ، كما JFrame هو حاوية مرئية بالفعل التي تغير فيها الأطفال.

الاقتباس javdoc من validate()

يتم استخدام طريقة التحقق من الصحة للتسبب في حاوية لوضع مبلغها الفرعي مرة أخرى. يجب استدعاءه عند تعديل المكونات الفرعية للحاوية (يضاف أو إزالتها من الحاوية، أو تم تغيير المعلومات المتعلقة بالتخطيط) بعد عرض الحاوية.

  • العامل الثاني فقط يفعل بعض الانتظار ثم يحدد لون الخلفية إلى الأسود
  • تستخدم JPanel كما baseclass ل ImageLoadTest لإصلاح setBackground() التي لم أستطع العمل مع JComponent.

لذا فإن مشاكلك الرئيسية حيث لم تحدد الحجم المفضل للمكون وأنك لم تتصل validate() على ال JFrame بعد إضافة شيء إلى الحاوية المرئية بالفعل.

هذا يجب أن يعمل

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;
  }
}

أوصي بقراءة أول زوجين من الفصول "للعملاء الغنيين القذرة". كنت تستخدم التأرجح لسنوات، ولكن بعد قراءة هذا الكتاب هل فهم أخيرا تماما كيف تعمل آلية الطلاء في جافا تماما.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top