I am building a JavaFX app containing a few static tabs on a TabPane, and during startup will be dynamically adding different tabs with different content as driven by a configuration as needed.
Note, each dynamic tab could be different from each other and I will need to selectively pick which one of these dynamic tabs I want to instantiate/add.
I am using Scene Builder to design the GUI for the bulk of the app. So far everything for the static tabs works fine. Here's where my challenge starts.
How do I leverage Scene Builder to design the dynamic tabs, and only instantiate those tabs as desired at run time as configuration dictates?
Thanks Al
I would put the content of each tab into its own FXML file. You can load the ones that are always loaded in the "main" FXML file, using <fx:include>. Then in the initialize() method of the controller for the main fxml, read the configuration and load the other fxml files you need.
Something like
Main.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.TabPane?>
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="MainController">
<center>
<TabPane fx:id="tabPane">
<Tab>
<fx:include source="StaticContent1.fxml"/>
</Tab>
<Tab>
<fx:include source="StaticContent2.fxml"/>
</Tab>
<!-- etc -->
</TabPane>
</center>
</BorderPane>
and
MainController.java
public class MainController {
#FXML
private TabPane tabPane ;
public void initialize() {
Configuration config = readConfiguration(); // (pseudocode)
if (config.shouldLoadTab1()) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("DynamicTab1.fxml"));
Tab tab = new Tab("Some title");
tab.setContent(loader.load());
tabPane.getTabs().add(tab);
}
// etc
}
}
The FXML files for each of the tabs (whether "static" or "dynamic") would just contain the content of the tab (not the tab pane, which is already defined in the main fxml file, or the tabs, which (the way I have set it up) are defined either in the main FXML or by the controller). So you would just have something like
StaticContent1.fxml
<?xml version=1.0 encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com.fxml">
<!-- nodes... -->
</VBox>
Obviously you can use any layout pane you want in place of the VBox.
Related
I am creating a front end portal in ServiceNow that requires using g:evaluate to call on variables from different tables.
For example:
<g:evaluate var="jvar_user_name">
var gr = new GlideRecord('sys_user');
gr.get('sys_id', gs.getUserID());
gr.first_name;
</g:evaluate>
Is there a way to store a bunch of these somewhere and then call upon them as needed, much like UI Scripts for JS and Style Sheets for CSS? If so, how would I go about doing this?
Thanks!
Yes you should be able to do this by using UI Macros.
You could create a UI Macro called set_user_name_var like below:
<?xml version="1.0" encoding="utf-8"?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<g:evaluate var="jvar_user_name">
var gr = new GlideRecord('sys_user');
gr.get('sys_id', gs.getUserID());
gr.first_name;
</g:evaluate>
</j:jelly>
And then invoke the UI Macro any place where you can write jelly code, like so:
<g:set_user_name_var />
or alternatively:
<g:macro_invoke macro="set_user_name_var" />
And from that point on, the jvar_user_name jelly variable will exist and be able to be accessed.
For example:
<?xml version="1.0" encoding="utf-8"?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<g:set_user_name_var />
${jvar_user_name}
</j:jelly>
I have a razor script in Umbraco that is quite complex and I want at some point of it to render a macro in it.
The macro which is called SuggestionBox is actually a user control (.ascx) and traditionally this is referenced on the template using
<umbraco:macro Alias="SuggestionBox" language="cshtml" runat="server"></umbraco:macro>
But now I need to call it from the razor script instead so I tried;
#Html.Raw(umbraco.library.RenderMacroContent("SuggestionBox", Model.Id))
as well as:
#RenderPage("SuggestionBox")
No luck so far as I'm sure I'm using these wrongly.
I read somewhere it might be infeasible if the page is wrapped in a masterpage.
It works if I add it to the Template like I traditionally would:
<umbraco:macro Alias="EventsRenderer" language="cshtml" runat="server"></umbraco:macro>
<div class="talkingPointPanel">
<h3><umbraco:Item field="talkingPoinstSuggestionText" runat="server"></umbraco:Item></h3>
<umbraco:macro Alias="SuggestionBox" language="cshtml" runat="server"></umbraco:macro>
</div>
Where EventsRenderer renders the page that should ideally contain the SuggestionBox.
using
#Html.Raw(umbraco.library.RenderMacroContent("<?UMBRACO_MACRO macroAlias=\"SuggestionBox\" />", Model.Id))
Gives me this error:
<!-- Error generating macroContent: 'System.Web.HttpException (0x80004005): HtmlForm cannot render without a reference to the Page instance. Make sure your form has been added to the control tree.
at System.Web.UI.HtmlControls.HtmlForm.Render(HtmlTextWriter output)
at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
at umbraco.presentation.templateControls.Macro.Render(HtmlTextWriter writer)
at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
at umbraco.library.RenderMacroContent(String Text, Int32 PageId)' -->
Any ideas?
<umbraco:Macro runat="server" language="cshtml">#{
HtmlTextWriter writer = new HtmlTextWriter(this.Output);
var navigation = new umbraco.presentation.templateControls.Macro();
navigation.Alias = "Navigation";
navigation.MacroAttributes.Add("ulclass", "art-vmenu");
navigation.MacroAttributes.Add("level", 2);
navigation.RenderControl(writer); }</umbraco:Macro>
Try something like this. It works for me ... I have made a Navigation macro. Be Aware though your variables should be given in toLower, if caps are used, the parameters will not come through.
In Umbraco 4.10+ To call a macro inside Razor script, use:
#Umbraco.RenderMacro("macroNameHere", new { propertyName1 = CurrentPage.pageProperty }))
Try something like this:
#Html.Raw(umbraco.library.RenderMacroContent("<?UMBRACO_MACRO macroAlias=\"SuggestionBox\" />", Model.Id))
Im skinning a progressBar in Flex, and after reading a bit about it, I see that there is something called hostComponent.
Adobe site says:
"The host component is the component that uses the skin. By specifying the host component, Spark skins can gain a reference to the component instance that uses the skin by using the hostComponent property."
But, I still dont understand how this exactly works.
Any quick and practical explanation?
Thanks!
When you create custom components in the Spark architecture, you usually split them up into two parts:
an ActionScript class that contains the core functionality of the custom component. This class will usually extend SkinnableComponent or SkinnableContainer
an MXML skin class which is loosely associated with that ActionScript class and contains only the visual presentation of the component. This class should contain no real functionality and it should be trivial to substitute it with another skin.
The first of these two classes is referred to as the host component from the skin's point of view.
A simple example
Let's create a very simple panel by extending SkinnableContainer:
public class MyPanel extends SkinnableContainer {
[Bindable]
public var title:String;
}
As you can see, I made a property 'title' which we want to use to display a title in the Panel. Now let's create a skin that uses this property:
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Metadata>
[HostComponent("path.to.MyPanel")]
</fx:Metadata>
<!-- graphics for title bar go here -->
<s:Label text="{hostComponent.title}" top="5" left="5" />
<!-- graphics for panel content go here -->
<s:Group id="contentGroup" top="30" bottom="0" left="0" right="0" />
</s:Skin>
The hostcomponent is defined in the 'metadata' block and you see that we can use it to bind its properties into our visual representation. The 'contentGroup' is there because it is required by SkinnableContainer; this is were all the elements will go that you put inside the custom panel. So here's how to use it:
<myComps:MyPanel title="Panel title" skinClass="path.to.skins.MyPanelSkin">
<s:Label text="Hello Panel" />
<!--everything in here goes into the 'contentGroup'-->
</myComps:MyPanel>
For instance in Flex 4
?xml version="1.0"?>
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
private function setLabel():void {
trace ("the id is "+myButton.id);
myButton.id = "yourButton";
}
]]>
</fx:Script>
<s:Button id="myButton" label="Click Me" click="setLabel();"/>
the traces when the button is clicked twice are
'the id is myButton' followed by
'the id is yourButton'
Not just an idle query. I was hoping to change the id of custom components when populating a main app with them
I would assume that the id of the when set in mxml is the variable name which also sets the internal id (myButton.id = "myButton") Therefore you're able to change myButton.id to "yourButton" because id and variable name are different properties.
Weird one though I'll admit.
If you were to want to create custom components when populating your main app I would look in to a different approach than laying them all out in mxml. Perhaps creating the components in actionscript and setting them in mxml would be best? ( eg your main class is the mxml app and then you have a class behind that does the heavy lifting of creating the view, with all your custom named components )
Remember that MXML is parsed to ActionScript by mxmlc. mxmlc uses the ID attribute of the mxml tags to map to a public class member at compile time. Changing the runtime value of the ID field would have no change to the class structure.
Example:
<MyComponent>
<Button id="myButton" />
</MyComponent>
When compiled, mxmlc transforms it roughly to:
package {
class MyComponent {
[Bindable]
public var myButton:Button;
// Other junk for class init, etc would show here...
}
}
And is then compiled to SWF byte code. At which point the ID attribute is just an attribute and would have no bearing on the class's functionality. You'd have to actually assign a new Button instance to this.myButton to get it to change.
I've got a flex project that I'm working on. Currently I've got a popup that consists of another mxml file containing a form.
Once the form is filled in and submitted I'd like to run another function then the popup closes on the main mxml file, but I'm not sure how to go about doing this?
Here's my popup code:
private var weightadd:weight_add; //POP UP ADD WEIGHT FORM
private function weightAdd():void {
weightadd = new weight_add();
PopUpManager.addPopUp(weightadd,this,true);
PopUpManager.centerPopUp(weightadd);
}
Currently in my weight_add.mxml file I'm using a button to close the popup, I'd like have this button close the popup and then call a function in my main.mxml file - I'm just wondering how I go about doing this.
<mx:Button x="186" y="83" label="Cancel" styleName="formbutton" id="cancel_button" click="PopUpManager.removePopUp(this);"/>
I found this example which seem to do the trick
http://bubutripathy.wordpress.com/2007/02/09/popup-login-window