This may have been asked before but I have no idea how to word it to search for it.
I have a composite widget that has methods to update some of the widgets that make up the composite widget. When I add this composite widget to my panel I use a do while loop to pull data from an XML file and populate the composite data. When I instantiate the object each time to add the data it has a scope local to the do-while loop and I cannot call methods to update the data in the composite widget later on. Is there maybe a way to make an array of these composite widgets or another solution to be able to access the Widget?
Eric
Sure... use
List<Composite> widgetList = new ArrayList<Composite>();
// loop
widgetList.add(widget);
// end loop
widgetList.get(3).toString();
You'll want to use your custom class instead of Composite in the list generic... there's nothing stopping you from making data structures using widgets, just like you would with any other Java class.
If you are putting all your Widgets in that loop into one panel (presumably on of the subclasses of ComplexPanel, since you are adding many Widgets to one panel), then you could use one of the methods to access Widgets contained within a panel (assuming you add only those XML generated Widgets to the panel and nothing more):
com.google.gwt.user.client.ui.ComplexPanel.iterator() - returns an java.util.Iterator<Widget> you can use to traverse the list of Widgets within that Panel
com.google.gwt.user.client.ui.ComplexPanel.getWidgetCount() and getWidget(int index) can be used in a for loop to go through all the Widgets within a panel
So, let's look at an example:
VerticalPanel vPanel = new VerticalPanel();
// Fill up the vPanel using XML
Iterator<Widget> iterator = vPanel.iterator();
while(iterator.hasNext()) {
Widget w = iterator.next();
// Do something with w
}
// Or...
for (int i = 0; i < vPanel.getWidgetCount(); i++) {
Widget w = vPanel.getWidget(i);
// Do something with w
}
Of course, substitute VerticalPanel with the one you are you using :)
I definately recommend that you watch "Best Practices for Architecting GWT App" (from Google I/O 2009):
http://www.youtube.com/watch?v=PDuhR18-EdM
At about 24 minutes through it talks about how to write composite widgets using the MVP design pattern - although you should watch it all. Unfortunately it does not provide ready to use code snipets, but it does show you how to construct a framework to decouple your XML and UI objects nicely.
Related
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...
Lets say I have a layout panel having multiple textboxes.
Now I want to get a particular textbox in that panel by its name. How can I do that?
Thanks in advance.
One way to do it is to keep references of the textboxes in a hashMap while you create them.
You need to be careful about memory leaks though.
Another way is to use GWtQuery. You could access then by name any element in the DOM.
To get it without without GWTQuery you can do that:
Element element = Document.get().getElementById("myTextboxID");
TextBox box = new TextBox();
box.wrap(element);
Since gwt has not a css-selector implementation, I would use gwtquery aka gquery whose selector implementation performs really well.
Apart from many other features, it is able to return the widget asociated with any element:
import static com.google.gwt.query.client.GQuery.*;
[...]
// if the textbox is already a widget
TextBox b = $("input[name=first_name]").widget();
//Or it its an element
TextBox b = TextBox.wrap($("input[name=search]").get(0));
b.setValue("Foo");
I'm building a Qt plugin with multiple forms. I have a main form which has a tree widget placed on the left of the form.
I want to add items to this tree, such that clicking on these items would load the corresponding form on the same form. But I want the tree widget to be active so that I can select any other form also.
I was able to display a form on the main form using the following code:
Form1 *myform;
myform=new Form1(this);
myform->show();
where Form1 is the class of the form i intend to display. However this, covers up the tree widget also. And I have to do a string comparison of the item in tree being clicked to display the appropriate form.
Can someone please help me with this as I'm very new to Qt programming.
Thanks
ixM has a good suggestion. The first step should definitely be to use layouts in your main window - separating the tree from the rest of the window - where you are going to put your form. I would suggest using a splitter, because then the user can resize the two halves. You can set the splitter as the main widget of your CentralWidget in your main window.
QSplitter splitter = new QSplitter(CentralWidget);
splitter->setOrientation(Qt::Horizontal);
splitter->setHandleWidth(3);
splitter->setChildrenCollapsible(false);
MyTree= new QTreeWidget(splitter);
splitter->addWidget(MyTree);
Then add your tree widget to the splitter, which will be on the left side.
The next step is to add a placeholder widget on the right side of your splitter. We are also going to add a layout inside that widget. This layout is very important we are going to use it later.
QWidget WidgetRightSide = new QWidget(splitter);
QVBoxLayout setupLayout= new QVBoxLayout(WidgetRightSide);
setupLayout->setSpacing(0);
setupLayout->setContentsMargins(0, 0, 0, 0);
Now, at this point, this is where my answer really differs from the previous answer. You could use a QStackedWidget. That is certainly an option. The problem with that is that you have to create and load all your forms at the beginning. That uses way more memory, and will take longer to start up. That's not so bad if you have 2-5 forms, but when we are talking about 20, 30 or more forms that's really ugly.
So what I would suggest instead, is that when the user selects something in the tree, we will remove the old form, and add the newly selected form at that point.
When the selected item in the tree changes this is now what we have to do.
First, remove all the stuff from the previously selection form.
QLayoutItem *_Item;
while ((_Item = setupLayout->takeAt(0)))
delete _Item;
Next, figure out what form to show next, and create it.
QWidget *ActiveSetupForm = NULL;
if ( I need to load form 1)
{
ActiveSetupForm = new YourNewForm( WidgetRightSide);
}
else ...
And lastly, add your new form to our layout.
if(ActiveSetupForm)
{
setupLayout->addWidget(pActiveSetupForm);
}
Just as a side note. Layouts are tricky to do by hand. I would strongly suggest that you look into using the QtDesigner when you are creating your forms. It makes life soooo much easier. If you would like to know more about it check out this link.
I don't exactly understand what you are trying to achieve but the bit of code you are showing suggests that you do not use the layouts provided by Qt.
If your goal is to be able to dynamically load a form depending on the item that was clicked in the tree, you could achieve that by having a layout (let's say QHBoxLayout) where you would insert your tree and a QStackedWidget in which you could "store" each form (by using addWidget()) and choose which one you want to display by calling setCurrentIndex().
I have a Vertiacal panel object and This object contains many radiobuttons
So can i get those radioButton objects through Vertiacal panel object.
Maybe via iteration or ?
private void initCourse() {
coursePopupPanel.clear();
VerticalPanel verticalPanel = new VerticalPanel();
coursePopupPanel.setWidget(verticalPanel);
JsArray<JCourse> jCourseArray = JCourse.getList(stringMainData);
for (int i = 0; i < jCourseArray.length(); i++) {
final RadioButton courseRadioButton = new RadioButton("course");
courseRadioButton.setText(jCourseArray.get(i).getName());
courseRadioButton.getElement().setId(jCourseArray.get(i).getView());
verticalPanel.add(courseRadioButton);
//handler of course radio buttons
courseRadioButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
}
});
}
}
I have a reference to coursePopupPanel. but i have not reference to vertical panel, so can i get elements of vertical panel sonce holding reference to coursePopupPanel.
A GWT VerticalPanel is a subclass of ComplexPanel, an abstract class for Panels that contain more than one child widget. In ComplexPanel (and so inherited by VerticalPanel) are methods for getting the number of child widgets, getting references to them by index, and so on. You could build an iterator something like this:
Iterator<Widget> vPanelWidgets = myVerticalPanel.iterator();
while (vPanelWidgets.hasNext()){
Widget childWidget = vPanelWidgets.next();
if (childWidget instanceof RadioButton) {
...do stuff
}
}
I tend not to query a widget for its members. That ties me to the decisions I made about how to display the RadioButtons, following your example. What if you decide later to display your radio buttons in the cells of a FlexTable in order to control vertical and horizontal arrangement? To make that change means your widget iterator won't work. FlexTable is a Panel but not a ComplexPanel. The code I wrote above won't work if you decide to replace the VerticalPanel with a FlexTable.
If was to take something like this approach, I would keep my lists of related widgets (like a group of RadioButtons) in some sort of Java Collection. I pass that Collection to my presentation class, and inside there I write the code to do the layout. Usually that's a UiBinder class, with "#UiField(provided = true)" for these RadioButtons. The code in the presenter then associates the RadioButton elements of the Collection I passed in to the UiField placeholders for the RadioButtons in the UiBinder layout. So all my layout decisions are actually in the UiBinder xml file. If I decide to rip out my Vertical Panel and replace it with a FlexTable, I might not have to touch a single line of Java code, assuming I separated things out correctly.
[Actually, I would probably keep my decision to use RadioButtons inside the presentation layer, and inside the XML file in particular. That presentation class would fire a message on the EventBus to indicate the user had made a selection via a RadioButton ValueChangeHandler, and I wouldn't care if I used RadioButtons in a VerticalPanel or ToggleButtons in a FlexTable.]
You're not being to specific, add more details and maybe a code example.
I'm gonan try to guesstimate what you're trying to say here: You have a verticalPanel object. To it you add several radioButton objects. Later you want to retrive those radioButton objects (to maybe check if they're selected or not), right? There's several ways to do this. At any rate, why don't you check the code examples at the Gwt Showcase site here:
http://gwt.google.com/samples/Showcase/Showcase.html?locale=en_UM#!CwRadioButton
it has tons of visual examples, each with the attached code and css.
Since PopupPanel implements HasOneWidget interface you can coursePopupPanel.getWidget() to get a reference to your verticalPanel. And iterate widgets in it simply using
for (Widget w : verticalPanel){
//Do Stuff
}
I am using gwt 2.3 version.I am using gwt tree in my application.
Here is my code:
public void onModuleLoad() {
// Create a tree with a few items in it.
TreeItem root = new TreeItem("root");
root.addItem("item0");
root.addItem("item1");
root.addItem("item2");
// Add a CheckBox to the tree
TreeItem item = new TreeItem(new CheckBox("item3"));
root.addItem(item);
Tree t = new Tree();
t.addItem(root);
// Add it to the root panel.
RootPanel.get().add(t);
}
There is a item with check box.I want add image to this tree item.But I am not able to do this as I already added one widget check box.Is there any other way add image to tree item with check box??
TreeItem has a TreeItem(Widget w) constructor.
You can put anything you want in there. So write a small widget that has an image and text next to each other in a div and the Tree will render it correctly.
You are already using it in your example code. So just write one more widget that combines the CheckBox with an image in a FlowPanel or HorizontalPanel. Whatever you want.
This is something that made me whack my head for a while also. Basically I found 2 options:
Use SmartGWT, it has nice customizable tree widgets that let you change the pictures of the nodes:
http://www.smartclient.com/smartgwt/showcase/#tree_databinding_local
Use GWT's tree-image:
http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/user/client/ui/TreeImages.html
If you ask me, SmartGWT is somewhat demanding and rigid, and you might not like the fact that it doesn't let you go to the low leves like GWT does but it does have a nice set of customizable tree widgets. TreeImage on the other hand lets you still work with pure GWT (which I think is better overall), but it doesn't let you customize the tree as much as Smart GWT does