Dominik Gryszkiewicz

Dominik Gryszkiewicz Programista /
Projektant /
Analityk, SIPT

Temat: Problemy z kontrolką Menu.as

Witam,

Czy ma ktoś doświadczenie z kontrolką Menu.as? Jej opis i przykłady są pod adresami:
1) http://livedocs.adobe.com/flex/3/html/help.html?conten...
oraz 2) http://livedocs.adobe.com/flex/3/html/help.html?conten...

Kontrolka moim zdaniem jest bardzo uboga i mam problem z kilkoma rzeczami tj:

1) w jaki sposób dostać się do podmenu rozwijanych i jak dostać się do ich elementów? Np żeby określić na niektórych z nich ikony, rozmiary, style itd.
2) Na eventa MenuEvent.ITEM_CLICK mam podpiętą funkcje, która nie odpala się dla itemów, które mają submenu - moim zdaniem jest to bug - nigdzie nie znalazłem opcji, która umożliwia włączenie/wyłączenie tego. MenuEvent.ITEM_CLICK działa tylko dla itemów, które nie mają submenu
3) jak zrobić aby to menu było cały czas wyświetlane? bo po kliknięciu gdziekolwiek znika.

Z góry dzięki za pomoc ...Dominik Gryszkiewicz edytował(a) ten post dnia 01.02.11 o godzinie 12:14
Michał Grzegorzewski

Michał Grzegorzewski Adobe Flexpert i
właściciel firmy -
RIA-Develop

Temat: Problemy z kontrolką Menu.as

Witam,
w projekcie utwórz dwa katalogi

/assets/
/mx/controls/

do katalogu assets wrzuć obrazki z ikonami
topIcon.jpg
radioIcon.jpg
checkIcon.gif

plik /mx/controls/MyMenu.as

package mx.controls{
import flash.display.DisplayObjectContainer;
import mx.controls.Menu;
import mx.core.FlexGlobals;
/**
* ...
* @author mgr inż. Michał Grzegorzewski
* RIA Develop
*/
public class MyMenu extends Menu
{
public function MyMenu()
{
}
override public function hide():void
{
//super.hide();
}
public static function createMenu(parent:DisplayObjectContainer, mdp:Object, showRoot:Boolean = true):MyMenu {
var menu:MyMenu = new MyMenu();
menu.tabEnabled = false;
menu.tabFocusEnabled = false;
menu.owner = DisplayObjectContainer(FlexGlobals.topLevelApplication);
menu.showRoot = showRoot;
popUpMenu(menu, parent, mdp);
return menu;
}
}
}


Poniżej plik <!-- SimpleMenuControlIcon.mxml --> ze strony
http://livedocs.adobe.com/flex/3/html/help.html?conten...
ze zmodyfikowaną klasą z Menu na MyMenu

<?xml version="1.0"?>
<!-- SimpleMenuControlIcon.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

<mx:Script>
<![CDATA[
// Import the Menu control.
import flash.events.Event;
import mx.controls.MyMenu;
import mx.events.FlexEvent;
[Bindable]
[Embed(source="assets/topIcon.jpg")]
public var myTopIcon:Class;
[Bindable]
[Embed(source="assets/radioIcon.jpg")]
public var myRadioIcon:Class;
[Bindable]
[Embed(source="assets/checkIcon.gif")]
public var myCheckIcon:Class;
// Create and display the Menu control.
private function createAndShow():void
{
var myMenu:MyMenu = MyMenu.createMenu(null, myMenuData, false);
myMenu.labelField = "@label";
// Specify the check icon.
myMenu.setStyle('checkIcon', myCheckIcon);
// Specify the radio button icon.
myMenu.setStyle('radioIcon', myRadioIcon);
// Specify the icon for the topmenu items.
myMenu.iconField = "@icon";
myMenu.show(10, 10);
myMenu.addEventListener("hide", onHide);
}
private function onHide(e:Event):void
{
trace(e);
}
]]>
</mx:Script>

<!-- Define the menu data. -->
<mx:XML format="e4x"
id="myMenuData">
<root>
<menuitem label="MenuItem A"
icon="myTopIcon">
<menuitem label="SubMenuItem A-1"
enabled="false" />
<menuitem label="SubMenuItem A-2" />
</menuitem>
<menuitem label="MenuItem B"
type="check"
toggled="true" />
<menuitem label="MenuItem C"
type="check"
toggled="false"
icon="myTopIcon" />
<menuitem type="separator" />
<menuitem label="MenuItem D"
icon="myTopIcon">
<menuitem label="SubMenuItem D-1"
type="radio"
groupName="one" />
<menuitem label="SubMenuItem D-2"
type="radio"
groupName="one"
toggled="true" />
<menuitem label="SubMenuItem D-3"
type="radio"
groupName="one" />
</menuitem>
</root>
</mx:XML>

<mx:VBox>
<!-- Define a Button control to open the menu -->
<mx:Button id="myButton"
label="Open Menu"
click="createAndShow();" />
</mx:VBox>
</mx:Application>


To jeśli chodzi o automatyczne chowanie się menu. Można pewnie zrobić to bardziej elegancko grzebiąc w klasie mx.controls.Menu ale tak też powinno działać ;)

pozdrawiamMichał Grzegorzewski edytował(a) ten post dnia 01.02.11 o godzinie 14:37
Piotr Kubasiak

Piotr Kubasiak Flex developer

Temat: Problemy z kontrolką Menu.as

Style możesz sobie nadać każdemu obiektowi w menu ... ale musisz
a) nadać id
b) menuID.setStyle("openDuration", 30); - zmienia czas otwierania

tak samo możesz dla każdego pod menu ale nazwy styli jakie możesz zmienić musisz sobie w źródle kontrolki sprawdzić.
Dominik Gryszkiewicz

Dominik Gryszkiewicz Programista /
Projektant /
Analityk, SIPT

Temat: Problemy z kontrolką Menu.as

Piotr Kubasiak:
Style możesz sobie nadać każdemu obiektowi w menu ... ale musisz
a) nadać id
b) menuID.setStyle("openDuration", 30); - zmienia czas otwierania

tak samo możesz dla każdego pod menu ale nazwy styli jakie możesz zmienić musisz sobie w źródle kontrolki sprawdzić.

Problem w tym, że wszystkie elementy menu są tworzone automatycznie, postać menu przychodzi mi PHPowym WebServisem gdzie od razu otrzymuje strukturę o przykładowej postaci:
array -
[0] => array( 'label'=>'Menu item A',
'children'=>
array -
[0] => array('label'=>'submenuA - 1');
[0] => array('label'=>'submenuA - 2');
);
[1] => array( 'label'=>'Menu item B');

Takie array binduje od razu do menu jako dataProvider i otrzymuje Menu rozwijane postaci:

Menu item A>
- submenuA - 1
- submenuA - 2
Menu item B

Mam nadzieje, że powyższy przykład został przedstawiony zrozumiale.

No i problem w tym, że:
1) Nie definiuje tutaj struktury XML dla Menu tylko otrzymuje ją WebServisem
2) Może wystarczy zdefiniowac jakies atrybuty które normalnie szły by do XMLa?

I nie ma za bardzo możliwości dostania się do elementów menu, a jeśli chodzi o ikony to również nie mam ich danych tylko tworzone są dynamicznie - obrazki przekazywane są jako byte array i cała implementacja jest w iconFunction które na podstawie tego byte array tworzy Class i zwraca ikone.

Obecnie najważniejszą kwestią dla mnie jest dostanie się do elementów obiektu klasy Menu - ale nie do dataProvidera tylko do MenuItemRendererów - a dokładnie do submenusów
Michał Grzegorzewski

Michał Grzegorzewski Adobe Flexpert i
właściciel firmy -
RIA-Develop

Temat: Problemy z kontrolką Menu.as

Zauważ że strukturę nazwijmy ją "struct" w poniższym kodzie masz taką jaka przychodzi z PHP.
We flashu działasz na tej strukturze jak na tablicy php z tym że
do deklaracji tablicy asocjacyjnej używasz klasy Object a do indeksowanej
Array, czyli:

jak chcesz dodać pozycję "o" to deklarujesz obiekt w klamrach i postaci

var o:Object = {label:"String", children:new Array()};
var struct:Array = new Array(o);


tak samo możesz zdeklarować ikonę

{label:"String", children:new Array(), icon:bmp}


gdzie "bmp" to obiekt klasy Bitmap załadowany z ByteArray

samo odczytanie obrazka z ByteArray musisz zrobić przez klasę Loader

var loader:Loader = new Loader()
loader.loadBytes(myByteArray);

Więcej o klasie Loader tutaj:
http://help.adobe.com/pl_PL/AS3LCR/Flash_10.0/flash/di...

Poniżej przykład jak wcisnąć strukturę w dataProvider'a przy pomocy ArrayCollection
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="init()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Menu;

[Bindable]
private var dp:ArrayCollection;

public function init():void{
var struct:Array = new Array(
{label:"Submenu A-1", children:new Array(
{label:"A"},
{label:"B"})
}
);
dp = new ArrayCollection(struct);
myMenu.dataProvider = dp;
myMenu.show(10,10);
}
]]>
</mx:Script>
<mx:Menu id="myMenu" iconField="icon">
</mx:Menu>
</mx:Application>



żeby modyfikować wartości wewnątrz pola podczas renderowania musisz zaimplementować Obiekt Renderujący ItemRenderer i przypisać go do właściwości itemRenderer w Menu. Dostęp do danych uzyskasz przez Bindowaną własność 'data' którą musi implementować twoja klasa renderująca.
http://help.adobe.com/en_US/flex/using/WS2db454920e96a...Michał Grzegorzewski edytował(a) ten post dnia 03.02.11 o godzinie 00:47
Dominik Gryszkiewicz

Dominik Gryszkiewicz Programista /
Projektant /
Analityk, SIPT

Temat: Problemy z kontrolką Menu.as

Dzięki bardzo, ostatnią rzeczą którą mnie nurtuje jest "nieklikalność" elementów posiadających childreny - czy jest na to jakaś własciwość? Można to włączać/wyłączać? W menu mam dodanego event listenera MenuEvent.ITEM_CLICK i jeśli mam element menu nie posiadający childrenów (nie rozwijający się) to po kliknięciu na niego zdarzenie się odpala. Niestety elementy posiadające childreny nie odpalają tego zdarzenia na klik. W czym jest problem?
Dominik Gryszkiewicz

Dominik Gryszkiewicz Programista /
Projektant /
Analityk, SIPT

Temat: Problemy z kontrolką Menu.as

żeby modyfikować wartości wewnątrz pola podczas renderowania musisz zaimplementować Obiekt Renderujący ItemRenderer i przypisać go do właściwości itemRenderer w Menu. Dostęp do danych uzyskasz przez Bindowaną własność 'data' którą musi implementować twoja klasa renderująca.
http://help.adobe.com/en_US/flex/using/WS2db454920e96a...Michał Grzegorzewski edytował(a) ten post dnia 03.02.11 o godzinie 00:47

Witam ponownie,
rzeczywiście itemRenderer dla menu to jest rozwiązanie jednak u mnie również z tym występują problemy:

Na najprostszym przykładzie z menu testowym po dodaniu itemRenderera występują błędy, poniżej zamieszczam przykładowy kod menu z nie działającym item rendererem


<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" backgroundColor="#FFFFFF">
<mx:XMLListCollection id="myMenuData">
<mx:XMLList>
<menuitem label="File">
<submenu label="New" />
<submenu label="Open" toggled="true" openType="1">
<submenu label="Doc" openType="1" itemRenderer="Canvas" />
<submenu label="Pdf" openType="2" />
</submenu>
</menuitem>
<menuitem label="Help">
</menuitem>
</mx:XMLList>
</mx:XMLListCollection>
<mx:Script>

<![CDATA[
import mx.controls.Alert;
import mx.controls.Menu;
import mx.events.FlexEvent;
import mx.events.MenuEvent;
private function handleMenuClick(evt:MenuEvent):void
{
mx.controls.Alert.show(evt.item.@label);
//lastEvent.text = "Selection:" + evt.item.@label + ", Position: " + evt.index + " Type:" + evt.item.@openType;
}
protected function menu_creationCompleteHandler(event:FlexEvent):void
{
menu.show();
}
protected function menu_hideHandler(event:FlexEvent):void
{
menu.show();
}
]]>

</mx:Script>
<mx:Menu hide="menu_hideHandler(event)" id="menu" dataProvider="{myMenuData}" labelField="@label" creationComplete="menu_creationCompleteHandler(event)"
itemRenderer="TestMenuRend"
/>
</mx:Application>


oraz kod renderera TestMenuRend.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="true">
<s:Label text="{data}" />
</s:ItemRenderer>


Po uruchomieniu występuje błąd treści "TypeError: Error #1034: Type Coercion failed: cannot convert TestMenuRend@89a3c29 to mx.controls.listClasses.IListItemRenderer."

Bez deklaracji artybutu itemRenderer menu działa poprawnie. Czy ktoś wie w czym jest problem?
Michał Grzegorzewski

Michał Grzegorzewski Adobe Flexpert i
właściciel firmy -
RIA-Develop

Temat: Problemy z kontrolką Menu.as

s:ItemRenderer to przestrzeń dla sparka
dla mx fabryka renderująca IFactory musi implementować interfejs:
mx.controls.menuClasses.IMenuItemRenderer

wklej poniższy kod do pliku TestMenuRend.mxml i przeanalizuj co się dzieje nadpisując metodę set data(value:Object).

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
width="100"
height="25"
verticalScrollPolicy="off"
horizontalScrollPolicy="off"
implements="mx.controls.menuClasses.IMenuItemRenderer">
<mx:Script>
<![CDATA[
import mx.controls.Menu;

public function get menu():Menu
{
return null;
}

public function set menu(value:Menu):void
{
}
public function get measuredIconWidth():Number {
return 0;
};
public function get measuredTypeIconWidth():Number {
return 0;
}
public function get measuredBranchIconWidth():Number{
return 0;
}
override public function set data(value:Object):void
{
super.data = value;
if(value is XML)
myLabel.text = value.@label;
}
]]>
</mx:Script>
<mx:Label id="myLabel"></mx:Label>
</mx:Canvas>

Tworząc klasę renderującą dla Menu musisz zadbać o własną obsługę ikony
function get measuredIconWidth():Number
function get measuredTypeIconWidth():Number
function get measuredBranchIconWidth():NumberMichał Grzegorzewski edytował(a) ten post dnia 03.02.11 o godzinie 17:38

Następna dyskusja:

Flex scrollable menu + item...




Wyślij zaproszenie do