Getting row or TreePath of JTree node that is not in the viewport - jscrollpane

I have a JTree and a custom renderer.
The JTree is a tree of ip addresses by switch and port number.
I have a graph of the ip addresses.
When the user clicks on a graph line, I try to update the JTree to show the line selected by the user.
If the ip selected by the user's mouse click in the graph, the renderer contains that node and other actions happen easily because the row and TreePath are available.
If the list of ip's is large and some are scrolled out of the viewport, I am having a problem finding out what the row or treenode is for the object/ip that I want to select and show in the viewport.
I have an ActionEvent in the JTree that gets some of the text that makes up the nodes' text, returned from getUserObject().
I don't know how to find the row or TreeNode. If I could find them I could check if the row was visible and if not call makeVisible(treePath) - or use scrollPane.getViewport().getViewRect() and compare it to the rect of the treeNode.
Thanks for any tips or direction ...
Jim

I solved the problem in the following manner.
After expanding all the nodes I fill a hashmap that has ip as the key and row as the value.
When I get me event containing the ip, I look up the row in the hasmap.
This works whether the node/row is in the viewport or not.
As follows:
if ( ipRowMap.containsKey( ip )) {
row = ipRowMap.get( ip );
TreePath tp = getPathForRow( row );
Rectangle rtp = this.getPathBounds( tp );
Rectangle rsp = scrollPane.getViewport().getViewRect();
if ( !rtp.intersects( rsp)) {
scrollPane.getViewport().scrollRectToVisible( rtp );
}
}
This works the first time, but not every time.
But that will be a new post if I can't solve that problem. I think the scrollpane or viewport has changed in a way I am not handling.

I found a better method for working with a JTree.
The method above works ok for JLists.
Since I have a map of rows, given the row number there is a JTree specific call of Component.
scrollRowToVisible( row );
and the code becomes
if ( ipRowMap.containsKey( ip )) {
row = ipRowMap.get( ip );
scrollRowToVisible( row );
}

Related

Do I have to create a reference for each text I have in a panel, if I want to access them to modify?

I have a panel with 8 text field, 4 are used as descriptive field (what a label would do, basically), while the other 4 are modified with values.
I am creating a GameObject variable for every element that I have in the panel, using find to find the specific text element. I can leverage on the fact that each text object has only one text object attached to it, so I can address to it directly with GetComponent
panel_info = GameObject.Find("infopanel");
textfield1 = GameObject.Find("text_name");
textfield2 = GameObject.Find("text_age");
textfield3 = GameObject.Find("text_role");
textfield4 = GameObject.Find("text_field");
textfield1.GetComponent<Text>().text = "joe";
textfield2.GetComponent<Text>().text = "22";
textfield3.GetComponent<Text>().text = "striker";
textfield4.GetComponent<Text>().text = "attack";
While this works, I can't foresee myself creating 20-30 objects if a panel has more info to display.
Since I have the reference to the object Panel, is there a way to address directly the text field which is a child of the panel, using the text field name for example?
So if a panel has 4 text field, I can modify each of it addressing directly by name, and then using GetComponent<Text>().textto change the value.
You MUST NOT call GetComponent<Text>() each time you want to access/modify text.
This is an extremely basic fact about Unity.
It is immediately mentioned in the relevant manual entries.
Since you have 8 textbox and I don't know how long you update each one. It would be good if you cache all of them in the beginning of the game then use them later on without GetComponent<Text>(). This will improve performance a lot and make your frame-rate happy.
Array looks good for something like this. And you need to comment each one too.
public Text[] textBoxArray;
On the editor, Expand the "Text Box Array" and change the array Size to 8.
Now drag each GameObject with the text to the arrays in order. If you do it in order, you can easily remember their names and be able to access them in order.
For example, if the first text gameobecjt you dragged to the array is called text_name, the access it, you use textBoxArray[0]. The second text which is text_age can be accessed with textBoxArray[1]. .....
To make it easier for you later on, you should have multiple line comment that describes which array points to what.You do this so that when you return to modify your code months after, you won't have to look around in the Editor to find what points to what. For example:
/*
textBoxArray[0] = text_name
textBoxArray[1] = text_age
textBoxArray[2] = text_role
textBoxArray[3] = text_field
*/
No performance lost and that decreases the amount of code in your game.
Initializing the arrays by code instead of the Editor
Assuming you want to initialize the arrays by code instead of the Editor. You can do it in the start function like below.
public Text[] textBoxArray;
void Start()
{
//Create arrays of 8
textBoxArray = new Text[8]; //8 texts
//Cache all the Text GameObjects
textBoxArray[0] = GameObject.Find("/infopanel/text_name").GetComponent<Text>();
textBoxArray[1] = GameObject.Find("/infopanel/text_age").GetComponent<Text>();
textBoxArray[2] = GameObject.Find("/infopanel/text_role").GetComponent<Text>();
textBoxArray[3] = GameObject.Find("/infopanel/text_field").GetComponent<Text>();
}
You should notice that GameObject.Find() starts with "/" and that increases performance too as it will only search for Texts under "infopanel" instead of searching in the whole scene.
Assuming that your hierarchy is setup that all your TextMeshes are children of the panel, you could use the Transform.Find method to get each child, then it's TextMesh, and assign a value.
So, for example, if you wanted to assign the value "Joe" to the TextMesh attached to "text_name", which in turn is a child of "infopanel", you could do the following
panel_info = GameObject.Find("infopanel");
panel_info.transform.Find("text_name").GetComponent<TextMesh>().text = "Joe";

SAPUI5 VizFrame: How to get the selected data points

I used a VizFrame to display data in my project.
The normal behaviour of the VizFrame when you select data in the graph you see a popover with the data of the selected point. When you select more than one point the content of the popover is something like in the screenshot: popover content.
I tried using attaching myself to the SelectedData Event. The oControlEvent.mParameters contain the data nodes being currently selected for THAT event.
For example: I click node A => the node A is in the oControlEvent.mParameters. => OK
Then I click additionally on node B (so node A and B are selected) => only the node B is contained in the oControlEvent.mParameters. => not OK.
What I need is the set of all nodes that are currently selected in the graph, not just the one that triggered the event.
This information must be contained somewhere, as the Tooltip correctly shows "2 data nodes selected" after the user clicked B.
Thanks for your help.
the oControlEvent.mParameters.data, or oControlEvent.getParameter('data') will (correctly) only contain the elements that actually triggered the event. (may be more than one data point if you select several data points in one go by dragging a rectangular area over the data points)
if you need all currently selected data points, use oControlEvent.getSource().vizSelection() (here, getSource() will return the vizFrame)
Cheers, iPirat

Android Display a random Item from List without showing the ListView

I am practicing on this project called GetTours i got from github, now
I want to display random Item from the ListView without seeing the ListView. not only show random item from ListView, but also print the details of the items, the item contains Name, address and lat long value for the map marker.
is that even possible?
or maybe, Teach me how to create a list that contains a name, address and lat long value and how to display it. I am also planning of randomizing it every time i shake the device. I had an app that do shake an random with a single data array, now I want to randomize a place with Name, address and a Map marker in the said location per shake. please help!
A ListView is not needed here, save your items in a List :
ArrayList<Item> items = new ArrayList<Item>;
items.add(item1);
items.add(item2);
//...
Then select a random number with the maximum as the length of your list :
final int random = Random.nextInt(items.size());
And then, do what you need to do with the data :
Item randomItem = items.get(random);
nameTextView.setText(randomItem.getName());
priceTextView.setText("" + randomItem.getPrice());
//...

GWT 2.4 DataGrid automatic scrolling when selecting an item

I am using GWT 2.4's new DataGrid in a project. I configured the DataGrid with a pagesize of 50.
The available screen is not big enough to display all items and thus a vertical scrollbar is shown (this is actually the main purpose for using a DataGrid in the first place).
I attached a SingleSelectionModel to the DataGrid in order to be able to select items.
This works fine so far.
However I also have another widget with which the user can interact. Based on that user action a item from the DataGrid should be selected.
Sometimes the selected item is not in the visible screen region and the user has to scroll down in the DataGrid to see it.
Is there any way to automatically or manually scroll down, so that the selected item is visible?
I checked the JavaDocs of the DataGrid and found no appropriate method or function for doing that.
Don't know if this works, but you could try to get the row element for the selection and use the scrollIntoView Method.
Example Code:
dataGrid.getRowElement(INDEX_OF_SELECTED_ITEM).scrollIntoView();
The answer above works pretty well, though if the grid is wider than your window and has a horizontal scroll bar, it also scrolls all the way to the right which is pretty annoying. I was able to get it to scroll down and stay scrolled left by getting the first cell in the selected row and then having it scroll that into view.
dataGrid.getRowElement(dataGrid.getVisibleItems().indexOf(object)).getCells().getItem(0).scrollIntoView();
Don't have time to try it out, but DataGrid implements the interface HasRows, and HasRows has, among other things, a method called setVisibleRange. You just need to figure out the row number of the item that you want to focus on, and then set the visible range from that number n to n+50. That way the DataGrid will reset to put that item at the top (or near the top if it is in the last 50 elements of the list backing the DataGrid). Don't forget to redraw your DataGrid.
Have you already looked at this? If so, I'd be surprised that it didn't work.
Oh, and since this is one widget talking to another, you probably have some messaging set up and some message handlers so that when the user interacts with that second widget and "selects" the item, the message fires on the EventBus and a handler for that message fixes up the DataGrid along the lines I've described. I think you'll have to do this wiring yourself.
My solution, a little better:
dataGrid.getRow(model).scrollIntoView();
I got a Out of bounds exception doing the above.
I solved it getting the ScrollPanel in the DataGrid and used .scrollToTop() and so on on the ScrollPanel. However, to access the ScrollPanel in the DataGrid I had to use this comment:
http://code.google.com/p/google-web-toolkit/issues/detail?id=6865
As Kem pointed out, it's annoying the "scrollToRight" effect after the scrollIntoView. After me, Kem's solution gives a better behaviour than the base one as usually the first columns in a table are the more meaningful.
I improved a bit his approach, which scrolls horizontally to the first column of the row we want to be visible, by calculating the first visible column on the left before applying the scroll and then scrolling to it.
A final note: Columns absolute left is tested against "51". This is a value I found "experimentally" by looking the JS values in the browser's developer tool, I think it depends on the table's style, you may need to change/calculate it.
Below the code:
public void scrollIntoView(T next) {
int index = datagrid.getVisibleItems().indexOf(next);
NodeList<TableCellElement> cells = datagrid.getRowElement(index).getCells();
int firstVisibleIndex = -1;
for(int i=0; i<cells.getLength() && firstVisibleIndex<0;i++)
if(UIObject.isVisible(cells.getItem(i)) && (cells.getItem(i).getAbsoluteLeft() > 51) && (cells.getItem(i).getAbsoluteTop() > 0))
firstVisibleIndex = i;
cells.getItem(firstVisibleIndex>=0? firstVisibleIndex : 0).scrollIntoView();
}

Loading two template files of same module in two positions

I am working on a new project and I am using Joomla version 1.5.22.
I need to display one horizontal search form in the middle of home page and the same search form in vertical style in all other pages but in left position.
So what I did is, I created two template files one for horizontal search(horizontal.php) and other for vertical search (vertical.php) and in mod_modulename.php I tried to load the respective modules based on a certain condition and changed the position left or middle according to it. The positions are changed in the database to get effected in the admin panel.
if(condition) {
modModulenameHelper::changeToVertical($position);//to change position in database to left
require( JModuleHelper::getLayoutPath( 'mod_modulename', 'vertical'));
}
else {
modModulenameHelper::changeToHorizontal($position);//to change position in database to middle
require( JModuleHelper::getLayoutPath( 'mod_modulename', 'horizontal'));
But I am not getting the correct output. It is loading the respective modules based on the condition. But the position is not assigned at first. And if I press Ctrl+F5 or refreshes, the page will be loaded with the desired output.
Why is this happening? Any Solution??
The problem is that you are changing the position after the fact. By the time you are changing the position, Joomla has already assigned the module to a position. It's an order of operations thing.
Instead, why not just use 2 instances of the module? Rather than going through this trouble, simply add a parameter to the module that allows you to select horizontal or vertical, then assign one to the home page menu item and another to the rest of the pages. This would also allow for putting the module in other positions instead of hard coding it in to the module.