I want to create own widget that will be able to interpret the text between start and end tag, eg:
<p1:Btn ui:field="open" >Open</p1:Btn>
Now the UI binder throws error:
Unexpected text in element: "Open" Element <p1:Btn ui:field='open'> (:44)
I supose that the widget have to be somehow marked to allow elements inside.
The second thing is how read the element between tags.
Your widget needs simply implement the HasText interface.
Related
How can I use condition in widget? I did it with empty widget like container() or Text() but when I put empty Widget in row() and give spaceBetween of MainAxisAlignment it takes their own space without any showing. Searching on the internet I think there are only the old info so that's not working anymore (if I am wrong I'm really sorry).
If conditions are not allowed and I do not want to show the widget - How can i do that?
If i understand correctly, you want to render Row conditional with size of childrens.
List<Widget> elements = []
Row(children: elements)
First option is to initiate elements inside your initState(){} method.
Another one, if you want to change it dynamically, then you have to know about setState(){} method and how key works, that is optional attribute of all Stateful/Stateless Widgets.
I have a method that returns one of two stateful widgets, based on the value of an enum. However, even though I can see via the debugger that the "correct" widget is being returned, the UI only ever shows the first one that is rendered. It seems the state object is somehow being shared across different instances of the widget, or I'm missing something.
Widget _buildInfoCard(LoginStatus status) {
switch(status) {
case LoginStatus.LOGIN_FAILED:
return InfoCard("Login failed, please check your username and password.");
default:
return InfoCard("Please login with your username and password");
}
}
I expect that the displayed infocard will have the text that corresponds to the text of the returned info card, but the default case always presents. I've stepped through the code, the correct widget is returned, and the default widget is not returned after that, so it should be displayed, but does not.
EDIT:
The _buildInfoCard method gets called inside of a streambuilder.
You need to give each instance of your StatefulWidget a key otherwise they may share state, something like this:
Widget _buildInfoCard(LoginStatus status) {
switch (status) {
case LoginStatus.LOGIN_FAILED:
return InfoCard(
key: ValueKey(status),
message: "Login failed, please check your username and password.",
);
default:
return InfoCard(
key: ValueKey(status),
message: "Please login with your username and password",
);
}
}
Very good article about why we need keys here: https://medium.com/flutter/keys-what-are-they-good-for-13cb51742e7d
For anyone with the same issue - follow the link provided by Jordan Davies, then watch episode 2 of Flutter 101 on YouTube for more information.
The issue is that as you construct your widget tree, the flutter framework translates those widgets into elements, which it then uses to render the UI.
When the flutter framework is constructing the element tree, it looks at each widget and compares the widget type to the element type at a given position in the tree. If the types are the same, flutter may re-use the element.
Stateful widgets have a long-lived state object, they may not get deleted with the wrapping element when a new one added to the element tree. In this case, the newly returned widget may use an existing state object from a previously rendered stateful widget.
The solution is as Jordan suggested, use keys to prevent this from hapenning, or use stateless widgets. There are other methods on Stateful widgets that may work as well, but Jordan's answer best addresses my expectations.
Is there some method which tells you the line number and column number of a Text widget in Perl/Tk?
According to the documentation, the widget has a method index() which returns the "line.char" of various positions in the widget. Pass it the name of the special mark "insert" to get the current position of the insertion cursor. Pass it the name of the special mark "current" to get the current position on the mouse.
Your question doesn't make it clear which of the two you want.
I would like to print a GWT widget which extends Composite. This widget is composed of a grid whose cells are built with a ListDataProvider. When the user clic on a button print, the widget to print is built. Once this is done, I launch the print:
Element element = widgetToPrint.getElement();
String content = element.getInnerHTML();
print(content);
public static native boolean print(String content)
/*-{
var mywindow = window.open('', 'Printing', '');
mywindow.document.write('<html><head><title>Test</title>');
mywindow.document.write('<link rel="stylesheet" href="/public/stylesheets/ToPrintWidget.css" type="text/css" media="all"/></head><body>');
mywindow.document.write(content);
mywindow.document.write('</body></html>');
mywindow.print();
return true;
}-*/;
So, here is my problem:
The window which is opened by this method contains the core of the widget (built by the UI Binder), but some children are missing...
If I look inside the ListDataProvider and its related FlowPanel, the data are consistent, i.e. I've got several item in my list and in the flowPanel.
Consequently, it should be visible on the printing window...
I thought that maybe the problem was related to the method used to print the widget, so I also tried to add this widget into a dialogbox just before launching the print, to see if the widget was properly built... and it was.
So my widget displays well on a dialogbox, but if I try to give its innerHTML to the print method, by using getElement(), some widgets are missing... I've the feeling that the widgets which should have been built when the ListDataProvider changes are not properly set in the DOM... Somehow it works when I add the widget to a regular component, but it doesn't work when I have to give directly its innerHTML...
Do you have any idea ?
Thanks in advance.
Widgets are not just the sum of their elements, and DOM elements are not just the string that they are serialized to. Widgets are the element, and all events sunk to the dom to listen for any changes or interactions by the user. Elements then have callback functions or handlers they invoke when the user interacts with them.
By serializing the element (i.e. invoking getInnerHTML()), you are only reading out the structure of the dom, not the callbacks, and additionally not the styles set by CSS. This probably shouldn't be expected to work correctly, and as your experience is demonstrating, it doesn't.
As this is just a print window you are trying to create, event handling is probably not a concern. You just want the ability to see, but not interact with, the content that would be in that set of widgets. Styles are probably the main problem here then (though your question doesn't specify 'some children are missing' doesn't tell us what is missing, or give us any more clues as to why...) - you are adding one stylesheet in your JSNI code, but CellTable (which I assume you are using since you reference ListDataProvider) needs additional CssResource instances to appear correctly. I'm not sure how you can hijack those to draw in a new window.
Are you only using this to print content, not to let the user directly interact with the data? If so, consider another approach - use a SafeHtmlBuilder to create a giant, properly escaped string of content to draw in the new window.
String content = element.toString();
This will include all hierarchy elements in the node.
Just a reminder, all the GWT handlers will not work, and you have to sink all the events using DOM.
You might want to grab the outer HTML rather than the inner one.
GWT unfortunately has no getOuterHTML, but it's relatively easy to emulate.
If your widget is the only child within an element, then simply get the inner HTML of the parent element (w.getElement().getParentElement().getInnerHTML())
Otherwise, clone your widget's node add it to a newly created parent element, from which you'll be able to get the inner HTML:
DivElement temp = Document.get().createDivElement();
temp.appendChild(w.getElement().cloneNode(true));
return temp.getInnerHTML();
First thank you for your answers, it helped me to work out this problem.
I've almost solve the problem:
First, I do not use ListDataProvider anymore, because it wasn't clear for me when and how the view was refreshed. Instead I add my widgets by hand, which makes sense since, they are not going to move anyway.
Then, I define the style of my widgets using a common CSS stylesheet. However, in order to do it, I can't rely on CssResource, which was the way I was used to do it with GWT. I think that this comes from the JS method which gets lost by this kind of styles... Instead, I have to specify everything in a static CSS stylesheet, and to give it to the JS.
It works perfectly well, ie, I have my widgets, with thei styles, and I can print it.
But...
The color of some widgets depends on the color of the object that they represent. Consequently, I cannot write a generic CSS stylesheet... And as I said, I can't add a style using CssResource... Do you have any ideas on the way to handle that ?
To make sure I'm clear on the way I'm adding styles, here is an example:
Label l = new Label("Here is a cell in my grid to be printed");
l.addStyleName("PrintLineCell-kind_1");
With, in a public CSS stylesheet:
.PrintLineCell-kind_1{
background-color: red;
}
I hope there is a better way than to write 300 styles to cover 300 different colors...
I created a widget that is a subclass of Composite and has a com.extjs.gxt.ui.client.widget.Viewport in it. Into this viewport I added my header component, a LayoutComponent (initially empty) and my footer component. I initialized the composite widget by calling initWidget at the end of the constructor that sets everything up ... something like this (some code removed for readability):
public class MyComposite extends Composite {
...
public MyComposite(...) {
viewport = new Viewport();
viewport.add(new Header());
content = new LayoutContainer();
viewport.add(content);
viewport.add(new Footer());
initWidget(viewport);
}
public void show(Widget... widgets) {
content.removeAll();
for (Widget widget: widgets) content.add(widget);
}
}
Then I add an instance of this to the RootPanel:
MyComposite myComposite = new MyComposite(...);
RootPanel.get("myComposite").add(myComposite);
And guess what... that works! I see it. The header shows, the footer shows, and the content is blank at this point. Good. Then I make the call to show and add stuff to it. Not exactly as follows but for example:
myComposite.show(new Label(...));
But nothing happens. The code does run, the add(...) method gets called from the show(...) method, there are no exceptions, but nothing (new) shows up. I don't use a Label, but that is not the problem (verified, that works elsewhere). When I inspect the DOM in the browser, I see that there is a div for the content, like there was initially, but it remained empty (i.e. no body content).
What am I missing?
Thanks!
First off, are you extending GWT Composite or GXT Composite? If it is the GXT type you will need to call initComponent() on the viewport (rather than initWidget) as described here: http://dev.sencha.com/deploy/gxtdocs/com/extjs/gxt/ui/client/widget/Composite.html
Also, try adding the following line to the end of your show method:
content.layout(true);
This will force GXT to layour the contents of your LayoutContainer, and you should at least see the new elements added to the DOM. If they still don't appear on the screen you need to change your Layout of your LayoutContainer.