I have a TreeView that I've modified by putting an HBox in the "graphic" of the TreeItem label. This HBox contains a MenuButton. I want to be able to automatically select the TreeItem whenever focus is given to the MenuButton inside it -- something JavaFX doesn't do automatically. However, when I do something like this in the TreeView's cell factory:
menuButton.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> value, Boolean oldVal, Boolean newVal)
{
if(newVal.equals(oldVal))
return;
if(newVal)
{
TreeItem<FormationDataModel> treeItem = getTreeItem();
System.out.println("Setting selection to " + treeItem + "...");
treeView.getSelectionModel().select(treeItem);
}
}});
The focus on the menu button will often cause this Exception:
java.lang.NullPointerException
at javafx.scene.Scene$ScenePulseListener.synchronizeSceneProperties(Scene.java:2148)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2210)
at com.sun.javafx.tk.Toolkit$5.run(Toolkit.java:363)
at com.sun.javafx.tk.Toolkit$5.run(Toolkit.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:361)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:384)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:463)
at com.sun.javafx.tk.quantum.QuantumToolkit$9.run(QuantumToolkit.java:332)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:17)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:67)
at java.lang.Thread.run(Thread.java:744)
Does anyone have any idea what would cause this or how to fix it so that I can have a TreeItem selected automatically when a node inside the TreeItem gains focus?
For anyone else interested, this turns out to be one or more bugs in JavaFX 2.2 specifically where they override the implementation of the MultipleSelectionModel to fix OTHER bugs. In the process of doing that, they cause all sorts of problems because they automatically expand the children of any selected item. When you do that, many of the TreeItems are invalidated, causing all sorts of sync havoc. The workaround was to select items by INDEX instead of by OBJECT. That works perfectly fine.
Related
how to check if an component is already in the layout?
I have an 4x4 gridlayout
with some buttons
one button is to show an datagrid
one to show inputfields
what I try to do is
MenuBar.Command tablecommand = new MenuBar.Command() {
public void menuSelected(MenuItem selectedItem) {
output.setValue("clean components");
layout2.removeComponent(name);
layout2.removeComponent(name2);
layout2.removeComponent(button);
layout2.removeComponent(cp);
//layout2.removeComponent(grid);
//if layout2 !contains grid
layout2.addComponent(grid,1,2);
}
};
without check I get an exception
java.lang.IllegalArgumentException: Component is already in the container
at com.vaadin.ui.GridLayout.addComponent
when I click on the showgrid button the second time
the only thing I can find is ".equals(obj)"
You can look if the component has a parent.
If yes, then it's already in place somewhere.
https://vaadin.com/api/com/vaadin/ui/Component.html#getParent--
I Build a scrollViewer and its elements in my ViewModel, and it's built into a property FrameworkElement PageElement I rebuild the pageElement every time some event happens, I want to bind the PageElement to a real scrollViewer in the View so that whenever I change pageElement, it draws itself in it's view.
Let me give you a little armchair advice. I don't know the details of your project but the details in your question make me draw a few conclusions.
First, to have your view model create UI elements is not wrong. But it is really unusual. It sounds like you might be missing the concept of data template or data template selector.
Using a data template allows you to have a rich presentation of data that is built as the individual record is generated and rendered in a repeater or in a single content control.
Using a data template selector allows you to have various different presentations of data that using code-behind logic will switch between based on data or other criteria.
Ref on templates: http://blog.jerrynixon.com/2012/08/windows-8-beauty-tip-using.html
Second, to have your UI be re-generated as the result of an event being raised sounds like a short path to performance problems.
Every time you manually create elements and add them to the visual tree, you put your app at risk of binding lag while the layout is re-rendered. Run your app on an ARM and I bet you may already see it. Then again, a simplistic UI may not suffer from this general rule of thumb.
Because I do not know the event, I cannot presume it is frequently occurring. However, if it is frequently occurring, then even a simplistic UI will suffer from this.
Now to answer your question
Sherif, there is no write-enabled property on a scrollviewer that will set the horizontal or vertical offset. The only way to set the offset of a scrollviewer is to call changeview().
var s = new ScrollViewer();
s.ChangeView(0, 100, 0);
You cannot bind to a method, so binding to something like this is a non-starter without some code-behind to read the desired offset and calling the method directly.
Something like this:
public sealed partial class MainPage : Page
{
MyViewModel _Vm = new MyViewModel();
ScrollViewer _S = new ScrollViewer();
public MainPage()
{
this.InitializeComponent();
this._Vm.PropertyChanged += (s, e) =>
{
if (e.PropertyName.Equals("Offset"))
_S.ChangeView(0, _Vm.Offset, 0);
};
}
}
public class MyViewModel : INotifyPropertyChanged
{
private int _Offset;
public int Offset
{
get { return _Offset; }
set
{
_Offset = value;
PropertyChanged(this, new PropertyChangedEventArgs("Offset"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
But let me caution you. The offset will need to be based on something. And those variables may change based on the window size, the font size, scaling from transforms, and lots of other factors. The code above will work most of the time, but it will possible fail frequently on other devices.
So, what to do? My recommendation is that you code this in your code-behind, monitoring for whatever scenario you feel would require a scroll, and simply programmatically scroll it from bode-behind. Beware, though, programmatically scrolling a scrollviewer could make your UI confusing to the user.
You know your app. You will have to choose.
Best of luck!
I need to develop a control which is similar to the Nested Grid in the Smart GWT.
User will be having a column for expansion images, when user clicking on the image in a particular row, a sub grid has to be opened there itself. Here all remaining rows needs to move down.
How can i achieve that functionality? Can anybody give me some clues so that i can proceed.
I have already a grid which is a celltable with custom header(with search functionality implemented).
Thanks,
Saritha.
Create your nested widget (myNestedWidget) that you want to show. It should have a CSS style "position: absolute", unless your grid is added to the LayoutPanel (or similar), in which case you can position your widget directly. Let's call the parent widget of your grid gridParentWidget.
In your CellTable add the following handler:
myTable.addCellPreviewHandler(new Handler<myObject>() {
#Override
public void onCellPreview(CellPreviewEvent<myObject> event) {
if ("click".equals(event.getNativeEvent().getType())) {
if (event.getColumn() == 0) {
int top = myTable.getRowElement(event.getIndex()).getAbsoluteBottom();
int left = myTable.getRowElement(event.getIndex()).getAbsoluteLeft();
myNestedWidget.getElement().getStyle().setTop(top, Unit.PX);
myNestedWidget.getElement().getStyle().setLeft(left, Unit.PX);
gridParentWidget.add(myNestedWidget);
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
int height = myNestedWidget.getOffsetHeight();
myTable.getRowElement(event.getIndex()).getStyle().setHeight(height + "px");
]
});
}
}
});
}
This is obviously an outline of the solution. The details of the implementation may vary slightly depending on which widgets you use for your parent widget and your nested widget. If you change z-indexes somewhere, you have to take it into account too. You also need to make sure that your nested widget fits into the width of your grid, or you'll need to wrap it in a ScrollPanel and set a width to it explicitly.
I have to port some legacy code, that uses modal dialog boxes all over the place to Metro/WinRT (using C++/CX). Because these dialog boxes provide their own message loop (using DialogBoxParam()), the calling code will wait until the user has clicked a button on the message box.
I'm currently trying to write a replacement for the old message box class, that uses XAML and the popup control. To reproduce the same behavior, I have to wait in the calling thread, but also have to keep the UI responsive. I've found out, that CoreDispatcher::ProcessEvents() can be used in a loop, to keep processing events (yeah I realize that this isn't very beautiful, but I don't want to change all of our legacy code to a new threading model). However I'm running into an issue that keeps crashing my app.
Here is a minimal example that reproduces the issue (just create a XAML app and wire this to a button):
void CPPXamlTest::MainPage::Button_Click_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
bool cancel = false;
auto popup = ref new Popup();
auto button = ref new Button();
button->Content = "Boom";
auto token = (button->Click += ref new RoutedEventHandler([&cancel] (Object ^, RoutedEventArgs ^) { cancel = true; }));
popup->Child = button;
popup->IsOpen = true;
while (!cancel)
{
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
popup->IsOpen = false;
button->Click -= token;
}
This seems to work well for the first one or two tries of opening and closing the popup, using the two buttons. After a few tries however, the application will instantly crash deep in Windows.UI.Xaml.dll, while trying to dereference a null pointer. I can also reproduce this in C# (with practically the same code).
Does anyone have an idea, what is going on in here? Or a suggestion for an alternative approach?
If anyone is interested: I asked the same question a few days later on the MSDN forums and got a response there from a Microsoft employee:
http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/11fa65e7-90b7-41f5-9884-80064ec6e2d8/
Apparently the problem here is the nested message loop that is caused by calling ProcessEvents inside an event handler. It seems that this is not supported by WinRT, but instead of failing in a well-defined manner, this will or may cause a crash.
Alas this was the best and only answer I could find, so I ended up working around the problem, by dispatching the event handler (and a lot of other code) into another thread. I could then emulate the waiting behavior of DialogBox()/DialogBoxParam() (outside the main thread), by waiting on an event that was signaled when the user clicked/tapped a button on my XAML "dialog" popup.
A workaround that works fine for me is to replace the line:
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
with:
auto myDispatchedHandler = ref new DispatchedHandler([&](){
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
});
dispatcher->RunAsync(CoreDispatcherPriority::Normal,myDispatchedHandler);
For more info see this post at MSDN.
I am trying to implement MVVM, and are having issues with moving LoadOnDemand to my ViewModel using triggers and RelayCommands, I have the event firing and all,
but as it turns out it is possible to expand a node in the tree without having it selected (i have databound the SelectedItem property in my ViewModel), thus breaking the logic, since the onLoad animation will continue to spin.
If I instead do this:
private void HierarchyTreeControl_LoadOnDemand(
Object sender,
Telerik.Windows.RadRoutedEventArgs e){
RadTreeViewItem clickedItem = null;
clickedItem = e.OriginalSource as RadTreeViewItem;
if (clickedItem != null) {
...do load logic
in the code behind file. I have access to the expanding item (clickedItem). What am I missing?
Is it possible to do some sort of binding on the ExandingItem?
Any Help will be appreciated :)
Since you are not using a standard treeview, I cannot be sure this is relevant. But I have previously had success in binding a TreeViewItem's IsExpanded property to a viewmodel property, in which I loaded items when the value was set to true (and not already loaded).
Here is a useful link: One more platform difference more-or-less tamed