5 - Избиране

Рефакторинг

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

В класовете „MyRectangle“ и „MyEllipse“ имаме повтарящ се код. Той ще става все повече в бъдеще. Затова е добре да го изнесем в общ родителски клас, който да бъде наследен от всички класове описващи фигури. Нека този клас се казва „CommonPrimitive“. Към него ще прибавим поле „selected“, което ще показва дали фигурата е избрана.

obsht-kod

Класовете „MyRectangle“ и „MyEllipse“ наследяват „CommonPrimitive“. В тях остава само методът „draw“, като в него достъпът до частното поле „color“ вече става с публичния метод „getColor“. В конструкторите им просто викаме конструкторът на наследения (супер) клас.

MyRectangle

Остава да добавим (някои от) методите към интерфейса, за да можем да ги използваме там където имаме обекти от тип „Primitive“.

interfeis

Можем също да премахнем дублираният код за рисуване на фигури при влачене на мишката от метода „jPanelCanvasMouseDragged“. Този код се намира в метода „draw“ на всеки обект и е най-добре да си остане капсулиран там. За целта при всяко преместване на мишката вместо да рисуваме фигура ще създаваме нов обект и ще викаме метода му „draw“. Разбира се това е по-неефективен вариант, но по-добър от проектантска гледна точка.

vlachene-risuvane

В метода „GlobalVars.drawFigures()“ ще изчистваме цялото платно за рисуване (без очертанието му). За целта трябва да знаем неговия размер. В „GlobalVars“ добавяме полето „canvasSize“ и го използваме при изчистването.

 platno-izchistvane

Размера ще задаваме при неговата промяна.

platno-razmer

За сега приключваме с рефакторинга.

Избиране

Трябва по някакъв начин да различаваме избраните обекти. За целта нека (в „CommonPrimitive“) рисуваме около тях пунктирана рамка.

risuvane-ramka

„drawBorder“ извикваме от метода „draw“ на фигурите.

dobaviane-ramka

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

При натиснат бутон „Избиране“ и щракване върху фигура тя ще става избрана. Ако зад нея има други фигури те няма да се избират.
При натиснат бутон „Избиране“ и маркиране на област с мишката, всички обекти, които попадат в тази област ще бъдат избрани, включително тези, които са частично или изцяло зад най-предните фигури.
Натискането и задържането на бутона „Ctrl“ ще ни позволява да избираме повече от една фигура.
При създаването на нова фигура тя автоматично ще става избрана.

И така, при глобалните променливи добавяме още една, булева - „ctrlPressed“. Тя ще бъде истина, когато е настинат клавишът „Ctrl“.

Продължаваме с метода „deselectAll“ в „GlobalVars“, който ще прави неизбрани всички обекти.

deselectAll

Методът „GlobalVars.select()“ приема, като параметър правоъгълна област, проверява дали в нея се съдържат фигури и ако има такива ги отбелязва, като избрани. Ако правоъгълната област е с размер по-малък от 2x2 пиксела се проверява дали областта или точката принадлежат към най-предната (в тази област) фигура и ако е така, тя се избира. Всички други фигури стават неизбрани освен ако не е натиснат клавишът „Ctrl“.
Тъй като при щракването върху фигура обхождането на масива с фигури се прекратява при първата срещната, към която принадлежи точката на щракване, трябва предварително да се отбележат като неизбрани всички фигури (при условие, че клавишът „Ctrl“ не натиснат ).

select

 Метода „select“ ще викаме при пускане на мишката (в „jPanelCanvasMouseReleased“), ако е натиснат бутона „Избиране“.
Ако пък се създава нова фигура то тя се отбелязва, като избрана.

izvikvane-select

Остава да прихващаме събитията натискане и пускане на клавиш, за да проверяваме дали той е „Ctrl“ и да променяме полето „GlobalVars.ctrlPressed“. Ще правим това с компонента „jPanelCanvas“ - платното ни за рисуване.

Когато прихващаме събития свързани с клавиатурата от компоненти, които не са текстови полета, те предварително трябва да са получили фокус. Затова при натискане на бутона „Избиране“ (т.е. в „jToggleButtonSelectActionPerformed“), ще фокусираме платното за рисуване - „jPanelCanvas“.

С метода „jPanelCanvasKeyPressed“ обработваме събитието натискане на клавиш. Ако кодът на клавиша съвпада с кода на „Ctrl“ правим глобалната променлива ctrlPressed истина.
При пускане на клавиш (jPanelCanvasKeyReleased) я правим лъжа.

subitie-buton

Ако забелязахте от кода или от тестване на програмата, при щракване върху фигура, под която има друга такава, избрана става задната, а не както очакваме - предната. Нарочно съм ви оставил удоволствието да програмирате това сами. Става много лесно ако сте разбрали как работи кодът до тук :)

Промяна на цвета

Нека да добавим възможност за промяна на цвета на избран(ата|ите) фигури.

За целта добавяме надпис и панел, както направихме за текущия цвят. Нека името на панела да бъде „jPanelObjectColor“. (Припомням ви, че името се задава в секцията „Code“ или чрез щракване с десния бутон върху компонента.)

figura-cviat

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

figura-promiana-cviat

Казахме, че когато създадем нов обект, той автоматично ще става избран. Тогава в „jPanelCanvasMouseReleased“ трябва да променяме и цвета на новия панел.

suzdavane-cviat

Остава да сменяме цвета на панела, когато изберем обект/и. Тъй като те се избират в метода „select“ от класа „GlobalVars“ ни трябва достъп до панела от там. За целта ще създадем поле „jPanelObjectColor“.

jPanelObjectColor

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

prisvoiavane-jPanelObjectColor

Ето и използването му при избиране на обект („GlobalVars.select()“).

izbirane-promiana-cviat

Вече програмата ни започва да прилича на приложение за работа с векторна графика.

izgled-5

Оставям на вас да я тествате.

Ето го кода до тук: Trayangle-5.zip

А ето го и компилиран: Trayangle-5.jar
Можете да го стартирате от командния ред:

.../jdk1.6.0_22/jre/bin/java -jar Trayangle-5.jar

Коментари

Въпрос

Искам да питам за нещо не толкова свързано с този урок... Някой да знае как да си направя бутоните с изображение,а не с текст. От 30 мин. се опитвам да открия начин, но нещо не ми се получава.

Благодаря предварително!

Пишете на кирилица

Друг път пиши на кирилица, за да не се налага да редактирам съобщението ти.

Ако нямш кирилица и си под windwos погледни тук -> Гювечи от Инжинера. Или ползвай някой онлайн преобразувател: Кирилчо, kirilica.net, http://5ko.free.fr/bg/cyr.html

Съжалявам за кирилицата

 Съжалявам, за кирилицата. А иначе някаква идея за въпроса ми по-горе как става?

Добре, ето как става

Добре, ето как става:

Пишеш в http://google.com „swing image on button“;
Щракаш на втория резултат;
И там виждаш:

    ImageIcon cup = new ImageIcon("images/cup.gif");
JButton button2 = new JButton(cup);

:)

Добавяне на картинка с NetBeans

За да добавим картинка в Java програма чрез NetBeans, правим нов пакет „kartinki“.

paket-kartinki

Избираме бутона, (или друг компонент) върху който искаме да се покаже изображението (картинката) и в настройките му щракаме на трите точки вдясно от „icon“.

kartinka

В появилия се прозорец щракаме върху бутона „Import to Project…“ и избираме файла (в случая картинка).

vmukvane-v-proekta

След това избираме пакета, в който искаме да се добави файлът - „kartinki“.

postaviane-v-paket-kartinki

Щракаме на Finish, после на OK и сме готови.

kartinka-buton

В настройките на бутона от „horizontalTextPosition“ можем, да подравняваме текста спрямо изображението.

tekst-podravniavane

Благодаря много

Благодаря много за подробното обяснение! : ) 

Малък проблем...

,който забелязах преди малко.Нали идеята когато начертаем няколко фигури на екрана и примерно сме начертали,така че няколко фигури се засичат...когато тръгнем да селектираме би трябвало да се селектира този, който сме начертали последно..но тук се получава точно обратното, селектира се първата фигура.Опитах се да го оправя това, но ми е малко сложно когато "бъркам" в кода, който някой друг е писал....Ени хелп? 

Малко решение...

Цитат от по-горе:

Ако забелязахте от кода или от тестване на програмата, при щракване върху фигура, под която има друга такава, избрана става задната, а не както очакваме - предната. Нарочно съм ви оставил удоволствието да програмирате това сами. Става много лесно ако сте разбрали как работи кодът до тук :)

Ако нещо не ти е ясно по кода, питай.
Ако ти е трудно да бъркаш в чужд код най-добре си напиши свой :)

Ноу мор хелп абаут дис
Пириъд

Проблем със селектирането?

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

При мен няма проблем

Не е направено нарочно. Когато цялата фигура попада в маркираната област трябва да става избрана и при мен се получава. Ако обаче фигурата е завъртяна областта трябва да е малко по-голяма. Ако я маркираш точно по краищата може и да не се избере.

Ако можеш прати снимки на екрана за да видим какво точно се получава при теб.

Ясно

Не трябва ли принципно даден елемент да се селектира дори само малка част от него да попада в избраната от нас област.Или ти си го направил да се избира само ако целата фигура попадне в дадената област, тогава да се селектира.И ако може да ми разясниш малко как точно ти бачка метода за селектирането на една фигура,че нещо ми се губи как работи ще съм ти много благодарен! : )

Поздрави.

Избира се цялата фигура

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

Методът за избиране е обяснен по-горе. Задай конкретен въпрос. Какво точно не ти е ясно?

Не знам докъде си стигнал, но в следващата статия 6 - Преместване, завъртане методът „select“ е доста променен.

Хммм

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

Благодаря,че се занимаваш с нас! : )

Това става…

Когато имаш застъпени фигури и щракнеш върху тях променливата „area“ е „лъжа“, защото щракваш, а не маркираш област следователно се изпълнява кодът в „else“ блока. Там става избирането на най-горната/долната фигура.

Публикувай нов коментар

  • Адресите на уеб-страници и e-mail адресите автоматично се конвертират в хипервръзки.
  • Разрешени HTML tag-ове: <a> <p> <span> <div> <h1> <h2> <h3> <h4> <h5> <h6> <img> <map> <area> <hr> <br> <br /> <ul> <ol> <li> <dl> <dt> <dd> <table> <tr> <td> <em> <b> <u> <i> <strong><font> <del> <ins> <sub> <sup> <quote> <blockquote> <pre> <address> <code> <cite> <embed> <object> <param> <strike> <caption>
  • Линиите и параграфите се прекъсват автоматично.
  • Mark language-dependent sections with == lc == where lc (or lc-xx) is a language code, other or all.

Повече информация за опциите на форматиране

CAPTCHA
8 + 5 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.