C, PHP, VB, .NET

Дневникът на Филип Петров


* Местене на обекти чрез събития с NetBeans

Публикувано на 19 ноември 2015 в раздел УКИ.

В този урок ще покажем как можем да вмъкваме картинки и да местим обекти по екрана. Ще се запознаем и със събитието "натиснат бутон на клавиатурата". От самото начало подчертаваме, че това НЕ е правилният начин да се местят обекти от библиотеката Swing - това е само начин да го реализираме бързо и лесно за учебни цели. За повече информация вижте послеписа.

1. Създайте нов проект BallMover с JFrame в пакет ballmover.

2. С десен бутон върху създадения JFrame изберете Set Layout > Border Layout

1

BorderLayout е начин за подреждане на елементи по екрана така, че когато разтегляме прозореца (уголемяваме го или го смаляваме) елементите да се "движат" заедно с него и да остават на точните си релативни позиции една спрямо друга. BorderLayout дефинира пет зони на екрана на нашия JFrame: NORTH (северна - горе), SOUTH (южна - долу), EAST (източна - ляво), WEST (западна - дясно) и CENTER (централна - заема всичко свободно). Ние ще искаме да разделим екрана на две части. В долната - южна - част ще добавим два бутона. В горната част, която ще искаме да е по-голяма, ще добавим картинка, която ще местим чрез бутоните.

3. Добавете JPanel в южната част, както е показано на картинката по-долу. Най-простичко казано JPanel е контейнер, вътре в JFrame контейнера. Той също може да си има собствен Layout, т.е. да си дефинира зони.

2

4. Добавете още един JPanel в централната част на JFrame - ще видите, че така той ще заеме цялото оснаващо поле:

3

5. Цъкнете два пъти върху долния JPanel. Добавете два бутона. Преименувайте ги като moveLeft и moveRight и им сменете текста, както е показано на картинката:

4

6. В горния JPanel добавете JLabel. Именувайте обекта "theBall". Искаме да добавим иконка (картинка) на този JLabel, която всъщност ще е обекта, който ще местим по екрана. С десен бутон натиснете на този JLabel и отидете на Properties. Изберете свойството "icon" и натиснете на трите точки в края на екрана. В диалоговия прозорец изберете External Image и натиснете Import to Project... Намерете подходяща картинка и я вмъкнете в проекта. Последователността от действия е показана на следващата картинка:

5

7. Когато сте готови, картинката ще е добавена на екрана. В примера добавихме просто едно мъничко кръгче. Изтрийте текста на theBall, който ще стои в дясно от кръгчето. Би трябвало да се получи това:

6

8. Добавете actionPerformed действия на своите бутони, които извършват следното:

 private void moveLeftActionPerformed(java.awt.event.ActionEvent evt) { 
    int currentBallX = theBall.getLocation().x;
    int currentBallY = theBall.getLocation().y;
    theBall.setLocation(currentBallX-10, currentBallY);
 } 

 private void moveRightActionPerformed(java.awt.event.ActionEvent evt) { 
    int currentBallX = theBall.getLocation().x;
    int currentBallY = theBall.getLocation().y;
    theBall.setLocation(currentBallX+10, currentBallY);
 }

В случая getLocation() метода връща обект Point (точка), който от своя страна има свойства x и y. Тези числа указват къде вътре в контейнера се намира обекта. Горният ляв ъгъл на контейнера се приема за точка с координати (0,0). Точката (x,y) ще бъде горния ляв ъгъл на theBall.

С метод setLocation ние променяме местоположението на обекта. В случая moveLeft бутона ще го премества с 10 пиксела наляво, а moveRight бутона с 10 пиксела надясно.

9. Накрая искаме да добавим възможност при натискане на бутон на клавиатурата стрелка наляво да можем да местим топката наляво и съответно с бутон стрелка надясно да я местим надясно. Добавете Event на главния прозорец (JFrame), който е KeyPressed (натиснат клавиш на клавиатурата):

7

Двата вида събития от клавиатурата са натиснат бутон (keyPressed) и освободен бутон (keyReleased). Третия тип - keyTyped - включва двата в едно (натиснат и пуснат).

Добавете следния код:

 private void formKeyPressed(java.awt.event.KeyEvent evt) { 
    int currentBallX = theBall.getLocation().x;
    int currentBallY = theBall.getLocation().y;
    switch(evt.getKeyCode()){
      case java.awt.event.KeyEvent.VK_LEFT:
         theBall.setLocation(currentBallX-1, currentBallY);
         break;
      case java.awt.event.KeyEvent.VK_RIGHT:
         theBall.setLocation(currentBallX+1, currentBallY);
         break;
    }
 }

Ще забележите обаче, че при стартиране на програмата натискането на бутоните няма да работи. Проблемът е в това, че е в сила правилото "който обект в момента е на фокус, той приема KeyEvent". В случая един от двата бутона винаги ще е на фокус по подразбиране. За да се справим с този проблем, трябва да забраним на бутоните да отнемат фокуса от основната рамка. С десен бутон и Properties на всеки от двата бутона премахнете свойството "focusable":

8

Пуснете програмата - вече ще можете да движите топчето наляво-надясно и с клавиатурата!

Допълнителна задача 1: Добавете бутони и клавишни събития за местене на топчето нагоре-надолу;

Допълнителна задача 2: Добавете възможност в предишния проект - калкулатора - да въвеждате числата и операциите от клавиатурата.

П.П. Както написахме още в началото, показаният начин макар и работещ е неправилен. Това е така защото зависим от т.нар. "repeat rate" на клавиатурата. Топчето ни ще се движи толкова бързо, колкото е нагласен той в Windows. Освен това в самото начало има едно леко "зацикляне" - това е заради опцията "Repeat delay", както е показано на картинката по-долу:

Ако искаме да направим програмата както трябва и да няма тези проблеми, можем да се научим да местим обектите по правилния начин - с употребата на специален обект наречен Таймер. Той приема в конструктора си милисекунди за забавяне и код на събитие, което трябва да изпълни. Когато е стартиран (метод start()), той ще изпълнява събитието отново и отново в цикъл, като спазва указаното забавяне на всяка итерация.

Ще напишем само фрагмент от това как трябва да се преработи програмата. Първо ще създадем няколко член променливи (глобални променливи) - кодът се въвежда в самото начало след дефиницията на класа:

int directionX = 0;

int delay = 10;
Timer timerX = new Timer(delay, new ActionListener() {
   public void actionPerformed(ActionEvent ae) {
      theBall.setLocation( theBall.getX()+directionX,  theBall.getY());
      repaint();
   }
});

Първият таймер ще мести топката но X, а втория по Y (направете го!). Вече можем да променим събитията на бутоните по следния начин:

private void formKeyPressed(java.awt.event.KeyEvent evt) {                                
   switch(evt.getKeyCode()){
      case KeyEvent.VK_LEFT:
         directionX = -1;
         break;
      case KeyEvent.VK_RIGHT:
         directionX = 1;
         break;
   }
        
   if(directionX!=0){
      timerX.start();
   }
}

private void formKeyReleased(java.awt.event.KeyEvent evt) {                                 
  switch(evt.getKeyCode()){
     case KeyEvent.VK_LEFT:
        directionX = 0;
        timerX.stop();
        break;
     case KeyEvent.VK_RIGHT:
        directionX = 0;
        timerX.stop();
        break;
  }
}

Ще видите, че не само направихме анимацията МНОГО по-плавна, но и вече не зависим от настройките на клавиатурата. Това е правилният начин да реализираме тази програма. Проблемът от гледна точка на преподаването е, че кодът несъмнено се усложни и особено в частта си с дефиницията на таймера стана доста по-неприятен.

Допълнителна задача 3. Добавете втори таймер, който да движи топчето и нагоре/надолу.

 



Добави коментар

Адресът на електронната поща няма да се публикува


*