Актуализиране на моята графика

Тъкмо започвам да се запознавам с програмирането на Java и още по-скоро с графики и се натъкнах на някои проблеми. Искам да създам игра, подобна на крепостта на джуджетата, с цветен текст вместо изображения.

Ето какво имам досега:

public void paint(Graphics g) {
    super.paint(g);
    g.setColor(Color.red);

    for (int i = 0; i < 50; i++) {
        g.drawString("[Game goes here]", 100, 150);
        g.dispose();
        System.out.println(i);
    }
    g.dispose();
}

public GTest() {
    setSize(Toolkit.getDefaultToolkit().getScreenSize().width / 3, Toolkit
            .getDefaultToolkit().getScreenSize().width / 3 + 50);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);
}

public static void main(String[] args) {
    GTest myWindow = new GTest();
}

Искам да актуализира графиките на таймер, но не съм много сигурен как да направя това.

Знам, че това е доста обширен въпрос и ще се радвам да изясня всичко, което бихте искали да знаете.

РЕДАКТИРАНЕ:

Така че добавих този бит:

String[] letters = new String[10];
float fontsize = Toolkit.getDefaultToolkit().getScreenSize().width / 30;

public void paint(Graphics g) {

    g.setColor(textColor);
    setFont(getFont().deriveFont(fontsize));
    for(int i = 0; i < 10; i++){
        if((int) (Math.random() * 100) > 97){
            letters[i] = "w";
            textColor = new Color(0, 0, 100);

        }else{
            letters[i] = "l";
            textColor = new Color(0, 100, 0);
        }
        g.drawString(letters[i], i * 3, 10);
    }

Но сега изобщо не се показва. Добавих sysout след g.drawString и той го изпълни, така че не съм сигурен какъв е проблемът.


person Sam    schedule 10.09.2013    source източник
comment
Не отменяйте paint() на JFrame. Така НЕ ​​се рисува по поръчка. Прочетете урока за Swing за Персонализирано рисуване за правилния подход.   -  person camickr    schedule 11.09.2013


Отговори (2)


Когато правите нещо въз основа на таймер в Swing, javax.swing.Timer< /a> класът е най-добрият ти приятел.

Това е JavaDocs, което обяснява използването му доста добре, така че ето един пример.

public class GTest extends JFrame implements ActionListener {
    private Color textColor = Color.BLACK;
    private Random random = new Random();

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(textColor);
        g.drawString("[Game goes here]", 100, 150);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        textColor = new Color(random.nextInt(0x00ffffff));
        repaint();
    }

    public GTest() {
        setSize(Toolkit.getDefaultToolkit().getScreenSize().width / 3,
                Toolkit.getDefaultToolkit().getScreenSize().width / 3 + 50);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        Timer timer = new Timer(500, this);
        timer.setInitialDelay(0);
        timer.start();

        setVisible(true);
    }

    public static void main(String[] args) {
        GTest myWindow = new GTest();
    }
}

Това отново е вашият GTest клас, но този път цветът на текста се променя автоматично на всеки 0,5 секунди.

Забележете две основни промени:

  1. Сега конструкторът настройва нов екземпляр на Timer без първоначално забавяне, период от 500 ms и неговия слушател, настроен на this. Това означава, че този конструиран екземпляр ще слуша тиковете на този таймер.
  2. За да направим това, трябваше да внедрим интерфейса ActionListener. Това ни принуждава да напишем метода actionPerformed(), който се извиква всеки път, когато таймерът тиктака. В този метод ние променяме цвета на текста на произволен и извикваме repaint(), който впоследствие извиква нашия метод paint() и получава написания текст.

P.S. Не е нужно да dispose() вашия Graphics обект всеки път. Всъщност се казва и в неговия JavaDoc (подчертайте моя):

Графичните обекти, които са предоставени като аргументи на методите paint() и update() на компонентите, се освобождават автоматично от системата, когато тези методи се върнат. За ефективност програмистите трябва да извикат dispose(), когато приключат с помощта на Graphics обект само ако е създаден директно от компонент или друг Graphics обект.

person Petr Janeček    schedule 10.09.2013
comment
Чувствайте се свободни да задавате всякакви въпроси. - person Petr Janeček; 11.09.2013
comment
Това е наистина полезно. Също така се чудите как бихте променили размера на текста? Опитах двата параметъра за drawText, но това не проработи. - person Sam; 11.09.2013
comment
@Sam От този въпрос, например, setFont(getFont().deriveFont(18f)); трябва да работи в JFrame. Опитайте да търсите в Google java swing font size, за да получите повече отговори. - person Petr Janeček; 11.09.2013
comment
@sam За да промените размера на текста, трябва да промените шрифта. - person MadProgrammer; 11.09.2013
comment
Ако трябваше да използвате setFont(getFont... как бихте променили размера въз основа на променлива или screenSize или не бихте могли. - person Sam; 11.09.2013
comment
@Sam Частта 18f в последния ми коментар е число с плаваща запетая (равно на 18,0). Това е размерът, който зададох. Може обаче да бъде променлива или всяка друга дроб, стига да е float. - person Petr Janeček; 11.09.2013
comment
Ясно, разбрах. Благодаря ти много. - person Sam; 11.09.2013
comment
Не отменяйте paint() на JFrame. Така НЕ ​​се рисува по поръчка. Прочетете урока за Swing за Персонализирано рисуване за правилния подход. - person camickr; 11.09.2013

Първо, ако не създадете копие на контекста Graphics, не трябва да го изхвърляте. Това всъщност може да попречи на други части от вашия формуляр за кандидатстване да бъдат боядисани ;)

На второ място. Бих избегнал разширяване от контейнер от най-високо ниво, като JFrame, освен че ви позволяват да рисувате под декорацията на рамката/ръба на прозореца, те не са двойно буферирани.

Вместо това бих използвал нещо като JPanel вместо това и бих заменил неговия paintComponent метод. Това ще ви осигури автоматично двойно буфериране.

Тъй като Swing е рамка с една нишка, се очаква всички актуализации на потребителския интерфейс да се изпълняват в контекста на нишката за диапатчиране на събития.

Това прави живо малко трудно, когато става въпрос да се опитвате да правите неща като изчакване и синхронизиране на актуализации на боя.

За щастие, Swing предоставя javax.swing.Timer, което ви позволява да планирате събитие за известно време в бъдеще. Това също може да бъде настроено да се повтаря на редовни интервали.

Timer timer = new Timer(40, new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // perform your required actions here
    }
});

Сега, внимавайте, методът actionPerformed се изпълнява с контекста на EDT, това означава, че всяка продължителна/отнемаща време обработка, която правите тук, може да накара потребителския ви интерфейс да спре да рисува

Погледни

За повече информация...

person MadProgrammer    schedule 10.09.2013
comment
@Сам Това. Познанията за EDT са от решаващо значение при програмирането на Swing. Освен това относно рисуването директно в JFrame - всеки JFrame има панел със съдържание, който по подразбиране е JPanel. Или сменете своя собствен JPanel, или рисувайте директно върху предоставения. Вижте JFrame#setContentPane() и getContentPane(). - person Petr Janeček; 11.09.2013