![]() |
|
||||||||||
|
|||||||
|
|
« Предыдущая тема | Следующая тема » |
| Опции темы | Опции просмотра |
|
![]() |
![]() |
|
|||||
|
Регистрация: Mar 2013
Сообщений: 290
|
Всем привет.
Есть документ-класс Main, который отображает экземпляр класса Spritekeeper. Класс Spritekeeper отображает спрайт (создан в библиотеке и пролинкован) и текстфилд-кнопку (добавленную кодом). На "кнопку" добавлен слушатель, с помощью которого этот спрайт нужно удалить. Но удалять его нужно не напрямую, а посредством экземпляра отдельного класса Spritecloser. И вот, например, я пытаюсь сделать это так: Класс: Main.as package { import flash.display.*; import flash.events.*; public class Main extends Sprite { public var spriteKeeper:Spritekeeper; public function Main() { spriteKeeper = new Spritekeeper(); this.addChild(spriteKeeper); } } } Класс: Spritekeeper.as package { import flash.display.*; import flash.events.*; import flash.text.*; public class Spritekeeper extends Sprite { public var sprite1:Sprite1; public var spriteCloser:Spritecloser; private var controlObject:TextField; public function Spritekeeper():void { //--- отобразим sprite1 ---// sprite1 = new Sprite1(); sprite1.x = 100, sprite1.y = 100; this.addChild(sprite1); //--- отобразим кнопку ---// controlObject = new TextField(); controlObject.x = 100, controlObject.y = 300; controlObject.text = " REMOVE SPRITE "; controlObject.autoSize = TextFieldAutoSize.LEFT; controlObject.background = true; controlObject.backgroundColor = 0xFEC792; controlObject.border = true; controlObject.borderColor = 0xA05001; controlObject.selectable = false; this.addChild(controlObject); controlObject.addEventListener(MouseEvent.CLICK, removeSprite); //--- экземпляр очищающего класса ---// spriteCloser = new Spritecloser(); } private function removeSprite(e:Event) { spriteCloser.removeContent(sprite1); } } } package { import flash.display.*; import flash.events.*; public class Spritecloser extends Main { public function Spritecloser():void { //--- empty constructor } public function removeContent(mc:Sprite):void { trace("removeContent() started...", mc); spriteKeeper.removeChild(mc); } } } Цитата:
1. Почему происходит ошибка? Как ее исправить? 2. Насколько крив такой подход, и можно ли сделать как-то проще? |
|
|||||
|
[+1 16.07.13]
[+4 16.07.13] Регистрация: Oct 2005
Сообщений: 217
|
Ошибка у вас в классе Spritecloser, Вы расширяете главный класс Main, что и приводит к ошибке.
Вот так работает. package { import flash.display.*; import flash.events.*; public class Spritecloser extends Sprite { public function Spritecloser():void { //--- empty constructor } public function removeContent(mc:Sprite):void { if(mc.stage != null) { mc.parent.removeChild(mc); trace("removeContent() started...", mc); } } } } |
|
|||||
|
Регистрация: Mar 2013
Сообщений: 290
|
belv, большое спасибо, всё работает.
Хотелось бы еще вот такие моменты прояснить: 1. Свойство stage у спрайтов, насколько я понимаю, служит индикатором того, что данный объект находится в Display List, то есть виден на экране. Это правильно? Или оно имеет более широкий смысл. 2. Почему всё-таки нельзя наследоваться от Main? Могу лишь догадываться, что возникает какая-то логическая рекурсия, когда по кольцу все друг на друга ссылаются. 3. Если бы нужно было удалить не sprite1, а экземпляр spriteKeeper (который мы добавляем в Main) то как это можно было бы реализовать? Вот такой вариант: private function removeSprite(e:Event) { //spriteCloser.removeContent(sprite1); spriteCloser.removeContent(spriteKeeper); } Цитата:
|
|
|||||
|
[+4 06.05.14]
|
1. Более глобальный смысл
Это стейдж, он общий для всего. 2. Тут вопрос не почему, а зачем? У вас есть точка входа - это мейн, все вы вошли через него назад пути нет, зачем возвращаться? Да даже объяснять не надо - просто так нельзя и не нужно делать вот и все. 3. И по теме : какие то вы мутагенные связи придумываете, упрощайте себе жизнь - а не усложняйте , ведь в программировании все предельно просто, по сравнению с математикой ![]()
__________________
Марк Tween |
|
|||||
|
Регистрация: Mar 2013
Сообщений: 290
|
1. Хм, как-то это смущает. Не понимаю, как можно нечто такое крутое, глобальное и сакральное, как Stage, превратить в какое-то мелкое свойство класса. Это типа ссылка на Stage, ссылка на экземпляр Stage, или какие-то трюки со статическими переменными?
2. Тут вот какое дело. Я так понимаю, что для того, чтобы публичная переменная класса Main была видна в одном из связанных с ним классов, нужно чтобы этот связанный класс был наследником Main, ведь верно? А в моем примере получается (если не ошибаюсь) - композиция. То есть один класс имеет внутри экземпляр другого. А при таком раскладе, как я понимаю, нельзя увидеть переменную основного класса, пусть даже она public. 3. Это да, но это скорее по причине смутного представления о том, как нужно разбивать один класс на ряд других. Эту же задачу я могу легко реализовать в одном классе Main, не вопрос. Но я хочу понять, как сделать ее же посредством набора классов, так чтобы лучше изучить принципы наследования, композиции, видимости переменных, и т.п. И код разбитый на классы легче воспринимается. Я вот написал тут одну тестовую хрень чисто в Main классе, юзая много ифов, кейзов, циклов, листенеров... но потом смотрю на нее, и думаю: омайнготт, этож месиво какое-то, сложновоспринимаемое даже с комментариями, лол. |
|
|||||
|
[+1 16.07.13]
[+4 16.07.13] Регистрация: Oct 2005
Сообщений: 217
|
По первому пункту Вы верно мыслите, по-поводу рекурсии могу предположить, что да.Я никогда не задумывался над тем, что произойдет если расширить класс Main, не хочу писать свои мысли на этот счет, так как они могут быть ошибочны.Для того чтобы воспользоваться переменными другого объекта нужно иметь ссылку на этот объект, а так компилятор не знает где эта переменная или метод могут быть, он же не должен самостоятельно заходит в каждый класс и проверять, а нет ли тут той переменной? Даже более того, в любом другом классе может быть переменная с таким именем и как он должен будет решить, какую ему переменную использовать?
По 3 пункту не стоит разбивать классы так, чтобы каждый метод был в новом классе.Если Вам уже хочется, чтобы у Вас был в вооружении метод, который в любом месте можно использовать для удаления объекта со сцены, тогда задайте его как статический. Вот так: package { import flash.display.Sprite; public class Spritecloser { public function Spritecloser():void { //--- empty constructor } public static function removeContent(mc:Sprite):void { if(mc.stage != null) { mc.parent.removeChild(mc); trace("removeContent() started...", mc); } } } } package { import flash.display.*; import flash.events.*; import flash.text.*; public class Spritekeeper extends Sprite { public var sprite1:Sprite1; //public var spriteCloser:Spritecloser; private var controlObject:TextField; public function Spritekeeper():void { //--- отобразим sprite1 ---// sprite1 = new Sprite1(); sprite1.x = 100, sprite1.y = 100; this.addChild(sprite1); //--- отобразим кнопку ---// controlObject = new TextField(); controlObject.x = 100, controlObject.y = 300; controlObject.text = " REMOVE SPRITE "; controlObject.autoSize = TextFieldAutoSize.LEFT; controlObject.background = true; controlObject.backgroundColor = 0xFEC792; controlObject.border = true; controlObject.borderColor = 0xA05001; controlObject.selectable = false; this.addChild(controlObject); controlObject.addEventListener(MouseEvent.CLICK, removeSprite); //--- экземпляр очищающего класса ---// //spriteCloser = new Spritecloser(); } private function removeSprite(e:Event) { Spritecloser.removeContent(sprite1); } } } |
|
|||||
|
Регистрация: Mar 2013
Сообщений: 290
|
Спасибо на добром слове ^_^
Хотя конешно практические навыки только-только проклевываются, и вопросов на понимание очень много. Цитата:
Цитата:
Цитата:
Что если на этот mc повешен слушатель, например так: По идее, его тоже нужно удалить в этой статической функции. Ну, при корректном подходе по крайней мере (хотя наверное GC его удалит сам, но не знаю точно). И вот как тогда передать статическому методу имя этой функции? Прямой вариант не прокатывает: public static function removeContent(mc:Sprite):void { if(mc.stage != null) { mc.parent.removeEventListener(MouseEvent.CLICK, clickHandler); mc.parent.removeChild(mc); trace("removeContent() started...", mc); } } ... то возникают ошибки преобразования типов... И я не уверен можно ли вообще имя функции как параметер передать? Пробовал преобразовать в Object, но тоже implicit coercion ошибка идёт. |
|
|||||
|
[+1 16.07.13]
[+4 16.07.13] Регистрация: Oct 2005
Сообщений: 217
|
Наверное более правильно, в том классе где Вы его добавляете на сцену повесить на него слушатель события REMOVED_FROM_STAGE
|
|
|||||
|
Нуб нубам
модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
|
Цитата:
Цитата:
Цитата:
Цитата:
Если речь о мышиных событиях, то их не сможет посылать и принимать объект, не находящийся на стейдж. Да просто как вы по нему кликнете, если его нет на экране?))) // на самом деле конечно все технически серьезней, но не важно). При чем здесь GC вообще не понятно. Вы часом не путаете removeChild() с удалением объекта из памяти? Убрав объект со стейджа, Вы же его не удаляете. Он продолжает существовать в памяти, Вы можете добавить его в отображение снова в любой момент. Но даже если Вы собираетесь удалить этот объект совсем, нет никакого смысла убирать с него слушатели, пустота не посылает событий, знаете ли. То что Вы где-то краем уха слышали и не поняли про листенер и GC: когда Вы в контексте this добавляете объекту obj слушатель на события от него то Вы не сохраняете этим какую-то чудо-ссылку на obj, которая помешает GC этот obj удалить. Ровно наоборот. Вы отдаете в obj ссылку на handler, на функцию, описанную в том объекте, в котором написан этот код (this). Таким образом Вы передаете объекту obj ссылку на this в виде this.handler. Объект obj не может хранить ссылку на какой то handler в вакууме. Он запоминает ссылку на объект this и ЕГО метод handler. И пока в obj существует слушатель от this, Вы не можете удалить this. Удалить obj это никак не мешает. А после удаления obj, естественно, и ссылка в нем на this тоже удалится. Так что не надо выдумывать никакой охоты на ведьм.
__________________
Reality.getBounds(this); |
|
|||||||||
|
Регистрация: Mar 2013
Сообщений: 290
|
belv,
Цитата:
И закрадывается подозрение, что передача функции как параметра это нечто редкое, и не благославляемое по канону. Wolsh, не скрою, рад что вы отclickнулись. Цитата:
Цитата:
Думаю, вы имеете ввиду акт прописывания класса Main как документ класса. И тогда его экземпляр автоматически попадает в список отображения (то есть на стэйдж). А дальше уже по цепочке addChild'ов, тут понятно. Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Я понял так: removeListener нужен только когда мы удаляем this-экземпляр. Но если даже мы не внедрили этот метод, то GC удалит слушатель сам, хотя возможно с какими-то побочными эффектами. В случае же с obj-экземпляром: GC либо вообще не удалит этот слушатель (так как это не нужно), либо удалит - но без проблем. Последний раз редактировалось Fogflasher; 18.10.2013 в 11:23. |
![]() |
![]() |
Часовой пояс GMT +4, время: 23:43. |
|
|
« Предыдущая тема | Следующая тема » |
| Теги |
| классы , композиция , удаление экземпляров |
|
|