Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Сообщения за день
 

Вернуться   Форум Flasher.ru > Flash > ActionScript 3.0

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Ответ
Старый 16.10.2013, 11:26
Fogflasher вне форума Посмотреть профиль Отправить личное сообщение для Fogflasher Найти все сообщения от Fogflasher
  № 1  
Ответить с цитированием
Fogflasher

Регистрация: Mar 2013
Сообщений: 290
Post DisplayList: удаление одного экземпляра посредством другого

Всем привет.

Есть документ-класс Main, который отображает экземпляр класса Spritekeeper.

Класс Spritekeeper отображает спрайт (создан в библиотеке и пролинкован) и текстфилд-кнопку (добавленную кодом).
На "кнопку" добавлен слушатель, с помощью которого этот спрайт нужно удалить.
Но удалять его нужно не напрямую, а посредством экземпляра отдельного класса Spritecloser.

Нажмите на изображение для увеличения
Название: snap5494.jpg
Просмотров: 1418
Размер:	63.1 Кб
ID:	30103

И вот, например, я пытаюсь сделать это так:

Класс: Main.as
Код AS3:
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
Код AS3:
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);
 
		}
 
 
	}
 
 
}
Класс: Spritecloser.as
Код AS3:
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);			
		}
 
	}
 
}
Однако, такой вариант приводит к ошибке:
Цитата:
Error: Error #2136: The SWF file file:///С|/Classes%5Ftests/Main.swf contains invalid data.
at Spritekeeper$iinit()
at Main$iinit()
Два вопроса:
1. Почему происходит ошибка? Как ее исправить?
2. Насколько крив такой подход, и можно ли сделать как-то проще?

Старый 16.10.2013, 12:34
belv вне форума Посмотреть профиль Отправить личное сообщение для belv Найти все сообщения от belv
  № 2  
Ответить с цитированием
belv
[+1 16.07.13]
[+4 16.07.13]

Регистрация: Oct 2005
Сообщений: 217
Ошибка у вас в классе Spritecloser, Вы расширяете главный класс Main, что и приводит к ошибке.
Вот так работает.
Код AS3:
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);
			}
		}
	}
}

Старый 16.10.2013, 14:09
Fogflasher вне форума Посмотреть профиль Отправить личное сообщение для Fogflasher Найти все сообщения от Fogflasher
  № 3  
Ответить с цитированием
Fogflasher

Регистрация: Mar 2013
Сообщений: 290
belv, большое спасибо, всё работает.

Хотелось бы еще вот такие моменты прояснить:

1. Свойство stage у спрайтов, насколько я понимаю, служит индикатором того, что данный объект находится в Display List, то есть виден на экране. Это правильно? Или оно имеет более широкий смысл.

2. Почему всё-таки нельзя наследоваться от Main? Могу лишь догадываться, что возникает какая-то логическая рекурсия, когда по кольцу все друг на друга ссылаются.

3. Если бы нужно было удалить не sprite1, а экземпляр spriteKeeper (который мы добавляем в Main) то как это можно было бы реализовать?
Вот такой вариант:
Код AS3:
		private function removeSprite(e:Event)
		{
 
			//spriteCloser.removeContent(sprite1);
			spriteCloser.removeContent(spriteKeeper);
 
		}
... не работает, выдает ошибку:
Цитата:
1120: Access of undefined property spriteKeeper.
, видимо потому, что переменная spriteKeeper этому классу не видна (но ведь она же public, почему нет?).

Старый 16.10.2013, 16:27
in4core вне форума Посмотреть профиль Отправить личное сообщение для in4core Найти все сообщения от in4core
  № 4  
Ответить с цитированием
in4core
[+4 06.05.14]
 
Аватар для in4core

Регистрация: Mar 2009
Сообщений: 4,219
Записей в блоге: 14
1. Более глобальный смысл Это стейдж, он общий для всего.
2. Тут вопрос не почему, а зачем? У вас есть точка входа - это мейн, все вы вошли через него назад пути нет, зачем возвращаться? Да даже объяснять не надо - просто так нельзя и не нужно делать вот и все.
3. И по теме : какие то вы мутагенные связи придумываете, упрощайте себе жизнь - а не усложняйте , ведь в программировании все предельно просто, по сравнению с математикой
__________________
Марк Tween

Старый 17.10.2013, 11:20
Fogflasher вне форума Посмотреть профиль Отправить личное сообщение для Fogflasher Найти все сообщения от Fogflasher
  № 5  
Ответить с цитированием
Fogflasher

Регистрация: Mar 2013
Сообщений: 290
1. Хм, как-то это смущает. Не понимаю, как можно нечто такое крутое, глобальное и сакральное, как Stage, превратить в какое-то мелкое свойство класса. Это типа ссылка на Stage, ссылка на экземпляр Stage, или какие-то трюки со статическими переменными?

2. Тут вот какое дело. Я так понимаю, что для того, чтобы публичная переменная класса Main была видна в одном из связанных с ним классов, нужно чтобы этот связанный класс был наследником Main, ведь верно? А в моем примере получается (если не ошибаюсь) - композиция. То есть один класс имеет внутри экземпляр другого. А при таком раскладе, как я понимаю, нельзя увидеть переменную основного класса, пусть даже она public.

3. Это да, но это скорее по причине смутного представления о том, как нужно разбивать один класс на ряд других.
Эту же задачу я могу легко реализовать в одном классе Main, не вопрос. Но я хочу понять, как сделать ее же посредством набора классов, так чтобы лучше изучить принципы наследования, композиции, видимости переменных, и т.п. И код разбитый на классы легче воспринимается.
Я вот написал тут одну тестовую хрень чисто в Main классе, юзая много ифов, кейзов, циклов, листенеров... но потом смотрю на нее, и думаю: омайнготт, этож месиво какое-то, сложновоспринимаемое даже с комментариями, лол.

Старый 17.10.2013, 12:11
belv вне форума Посмотреть профиль Отправить личное сообщение для belv Найти все сообщения от belv
  № 6  
Ответить с цитированием
belv
[+1 16.07.13]
[+4 16.07.13]

Регистрация: Oct 2005
Сообщений: 217
По первому пункту Вы верно мыслите, по-поводу рекурсии могу предположить, что да.Я никогда не задумывался над тем, что произойдет если расширить класс Main, не хочу писать свои мысли на этот счет, так как они могут быть ошибочны.Для того чтобы воспользоваться переменными другого объекта нужно иметь ссылку на этот объект, а так компилятор не знает где эта переменная или метод могут быть, он же не должен самостоятельно заходит в каждый класс и проверять, а нет ли тут той переменной? Даже более того, в любом другом классе может быть переменная с таким именем и как он должен будет решить, какую ему переменную использовать?
По 3 пункту не стоит разбивать классы так, чтобы каждый метод был в новом классе.Если Вам уже хочется, чтобы у Вас был в вооружении метод, который в любом месте можно использовать для удаления объекта со сцены, тогда задайте его как статический.
Вот так:
Код AS3:
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);
			}
		}
	}
}
Его вызов
Код AS3:
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);
 
		} 
	}
}
А так Вы молодец, уже гораздо больше понимаете.Вы на верном пути.Удачи.

Старый 17.10.2013, 17:05
Fogflasher вне форума Посмотреть профиль Отправить личное сообщение для Fogflasher Найти все сообщения от Fogflasher
  № 7  
Ответить с цитированием
Fogflasher

Регистрация: Mar 2013
Сообщений: 290
Спасибо на добром слове ^_^
Хотя конешно практические навыки только-только проклевываются, и вопросов на понимание очень много.

Цитата:
Я никогда не задумывался над тем, что произойдет если расширить класс Main, не хочу писать свои мысли на этот счет, так как они могут быть ошибочны.
Ну вот, зато хотя бы понятно, что расширение Main это дурной тон, и практически не приветствуется.

Цитата:
тогда задайте его как статический
Попробовал, всё работает. Спасибо за наводку, а то я что-то вообще никогда статические методы и свойства не использовал, а вот щас всматриваюсь - клевая вещь.

Цитата:
mc.parent.removeChild(mc);
Не хотелось перегружать тему излишними вопросами, но есть еще один.
Что если на этот mc повешен слушатель, например так:
Код AS3:
sprite1.addEventListener(MouseEvent.CLICK, clickHandler)
По идее, его тоже нужно удалить в этой статической функции.
Ну, при корректном подходе по крайней мере (хотя наверное GC его удалит сам, но не знаю точно).

И вот как тогда передать статическому методу имя этой функции?
Прямой вариант не прокатывает:
Код AS3:
		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);
			}
		}
А если попробовать название функции передавать по типу строки:
Код AS3:
Spritecloser.removeContent(sprite1, "clickHandler");
... то возникают ошибки преобразования типов...
И я не уверен можно ли вообще имя функции как параметер передать?
Пробовал преобразовать в Object, но тоже implicit coercion ошибка идёт.

Старый 17.10.2013, 21:07
belv вне форума Посмотреть профиль Отправить личное сообщение для belv Найти все сообщения от belv
  № 8  
Ответить с цитированием
belv
[+1 16.07.13]
[+4 16.07.13]

Регистрация: Oct 2005
Сообщений: 217
Наверное более правильно, в том классе где Вы его добавляете на сцену повесить на него слушатель события REMOVED_FROM_STAGE
Код AS3:
Объект.addEventListener(Event.REMOVED_FROM_STAGE , _handlerRemovedFromStage);
private function _handlerRemovedFromStage(e:Event):void
			{
				Объект.removeEventListener(Event.REMOVED_FROM_STAGE , _handlerRemovedFromStage);
				Объект.removeEventListener(MouseEvent.CLICK, clickHandler);
 
			}

Старый 17.10.2013, 23:12
Wolsh вне форума Посмотреть профиль Отправить личное сообщение для Wolsh Найти все сообщения от Wolsh
  № 9  
Ответить с цитированием
Wolsh
Нуб нубам
 
Аватар для Wolsh

модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
Цитата:
1. Свойство stage у спрайтов, насколько я понимаю, служит индикатором того, что данный объект находится в Display List, то есть виден на экране.
Свойство stage дисплейных объектов указывает на единственный экземпляр Stage, представляющий область отображения окна флэшплеера. Это ссылка на объект, а не "индикатор". Будь это индикатор, он имел бы тип Boolean (то есть true или false) и назывался, например, hasStage. И это свойство не равно null только тогда, когда список отображения, в котором находится экземпляр DisplayObject, реально добавлен на стейдж. То есть, команда container.addChild(mc) не гарантирует, что у mc появится ссылка на стейдж. Это случится только тогда, когда ссылка на стейдж будет у container. А на него точно так же действует это правило, и так вплоть до экземпляра Main // Документ-класса.
Цитата:
2. Тут вот какое дело.
Всё не так. Кроме определения композиции. Оно верное))
Цитата:
Ну вот, зато хотя бы понятно, что расширение Main это дурной тон, и практически не приветствуется.
Если Вы расширите мейн, ваша флэшка просто не запустится, даже если удастся ее скомпилировать. Так что да, "не приветствуется". Попробуйте почитать хоть что-нибудь о наследовании. Это не такая уж мозговзрывательная тема. Отбросьте страх, что это сложно, и все станет очень простым. Вкратце — если Вы расширяете Мейн, то при создании экземпляра такого класса Мейн "внутри него" тоже будет создан. Не экземпляр Мейн, как при композиции, но сам этот экземпляр класса и есть экземпляр Мейн + что-то еще. Но создание этого экземпляра прописано в классе Мейн, и значит он будет создан опять. А в нем — еще один Мейн. А в нем — еще один экземпляр, который снова содержит Мейн, и т.д. Это бесконечный процесс. Плеер вывалится через 15 секунд или раньше, если забъет всю память.
Цитата:
По идее, его тоже нужно удалить в этой статической функции.
Ну, при корректном подходе по крайней мере (хотя наверное GC его удалит сам, но не знаю точно).
Нет смысла.
Если речь о мышиных событиях, то их не сможет посылать и принимать объект, не находящийся на стейдж. Да просто как вы по нему кликнете, если его нет на экране?))) // на самом деле конечно все технически серьезней, но не важно). При чем здесь GC вообще не понятно. Вы часом не путаете removeChild() с удалением объекта из памяти? Убрав объект со стейджа, Вы же его не удаляете. Он продолжает существовать в памяти, Вы можете добавить его в отображение снова в любой момент. Но даже если Вы собираетесь удалить этот объект совсем, нет никакого смысла убирать с него слушатели, пустота не посылает событий, знаете ли. То что Вы где-то краем уха слышали и не поняли про листенер и GC:
когда Вы в контексте this добавляете объекту obj слушатель на события от него
Код AS3:
obj.addEventListener(eventType, handler);
то Вы не сохраняете этим какую-то чудо-ссылку на obj, которая помешает GC этот obj удалить.
Ровно наоборот. Вы отдаете в obj ссылку на handler, на функцию, описанную в том объекте, в котором написан этот код (this). Таким образом Вы передаете объекту obj ссылку на this в виде this.handler. Объект obj не может хранить ссылку на какой то handler в вакууме. Он запоминает ссылку на объект this и ЕГО метод handler. И пока в obj существует слушатель от this, Вы не можете удалить this. Удалить obj это никак не мешает. А после удаления obj, естественно, и ссылка в нем на this тоже удалится. Так что не надо выдумывать никакой охоты на ведьм.
__________________
Reality.getBounds(this);

Старый 18.10.2013, 11:12
Fogflasher вне форума Посмотреть профиль Отправить личное сообщение для Fogflasher Найти все сообщения от Fogflasher
  № 10  
Ответить с цитированием
Fogflasher

Регистрация: Mar 2013
Сообщений: 290
belv,
Цитата:
Наверное более правильно, в том классе где Вы его добавляете на сцену повесить на него слушатель события REMOVED_FROM_STAGE
Попробовал, всё работает, благодарю.
И закрадывается подозрение, что передача функции как параметра это нечто редкое, и не благославляемое по канону.


Wolsh, не скрою, рад что вы отclickнулись.

Цитата:
Свойство stage дисплейных объектов указывает на единственный экземпляр Stage, представляющий область отображения окна флэшплеера. Это ссылка на объект, а не "индикатор".
Ок, в целом понятно.

Цитата:
когда список отображения, в котором находится экземпляр DisplayObject, реально добавлен на стейдж.
Имею сомнения в правильности понимания этой фразы. Как список отображения можно реально добавить на стэйдж?
Думаю, вы имеете ввиду акт прописывания класса Main как документ класса. И тогда его экземпляр автоматически попадает в список отображения (то есть на стэйдж). А дальше уже по цепочке addChild'ов, тут понятно.

Цитата:
Всё не так
Okay.jpg. Но как именно не так? То есть всё прямо-противоположно, тому что я там выше написал (а значит: публичные переменные и методы видны всем *.as-файлам в проекте, независимо от)

Цитата:
Попробуйте почитать хоть что-нибудь о наследовании. Это не такая уж мозговзрывательная тема.
Буду признателен если что-нибудь такое нуб-доступное посоветуете. Я кстати даже не в курсе, является ли тема наследования универсальной и независимой от языка программирования, или всегда есть специфика в реализации для AS3.0, например.

Цитата:
А в нем — еще один Мейн. А в нем — еще один экземпляр, который снова содержит Мейн, и т.д. Это бесконечный процесс.
Всё понял, прикольно : )

Цитата:
При чем здесь GC вообще не понятно. Вы часом не путаете removeChild() с удалением объекта из памяти? Убрав объект со стейджа, Вы же его не удаляете.
Да, попутал, действительно. Потому что исходил "из общих соображений", которые были у Мука и в некоторых камментах этого форума, согласно которым: "Если ты сделал где-то addListener, то ему должен соответствовать парный removeListener, а если это не так, то жди проблем и побочных эффектов".

Цитата:
...Таким образом Вы передаете объекту obj ссылку на this в виде this.handler. Объект obj не может хранить ссылку на какой то handler в вакууме. Он запоминает ссылку на объект this и ЕГО метод handler. И пока в obj существует слушатель от this, Вы не можете удалить this. Удалить obj это никак не мешает...
Не уверен что полностью понимаю практическое следствие из вышесказанного, в применении к целесообразности функции removeListener.
Я понял так: removeListener нужен только когда мы удаляем this-экземпляр. Но если даже мы не внедрили этот метод, то GC удалит слушатель сам, хотя возможно с какими-то побочными эффектами. В случае же с obj-экземпляром: GC либо вообще не удалит этот слушатель (так как это не нужно), либо удалит - но без проблем.


Последний раз редактировалось Fogflasher; 18.10.2013 в 11:23.
Создать новую тему Ответ Часовой пояс GMT +4, время: 23:43.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

Теги
классы , композиция , удаление экземпляров

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


Часовой пояс GMT +4, время: 23:43.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.