JavaFX - How to use multiple same type of event handlers on a single node - javafx

I've got 2 ListViews (A and B) of the same base type. What I need to implement is:
- user drags items from A, drops them into B
- user drags items from B, drops them into B(rearrangement).
The changes has to be saved in an sqlite table. 2 different sql query runs, so the drag and drops must have a different outcome.
If I do 2X B.setOnDragDropped, can I differentiate the 2 depending on where did the drag start?
Thanks for your help, much apprich folks

If you call setOnDragDropped(...) twice on the same node, the second handler will replace the first one (it is a set method, and works the same way as any other set method: it sets the value of a property).
You need something along the lines of
listViewB.addEventHandler(DragEvent.DRAG_DROPPED, e -> {
// handler code here...
});
You can determine the source of the drag inside the handler with
e.getGestureSource()
and see which node it matches to determine the course of action.

Related

QT Creator: Trigger a Slot with Code?

I may have worked myself into a corner but this sounded to me like a good idea at the time.
I have been developing an interface that permits a user to modify settings of a robotic device, i.e. speed, directions, force, etc. with a very large series of options in the form of ComboBoxes. The problem is that there are about a thousand of these things, in sub categories. e.g. Speed category x1, x2, x3, Y1, y2, etc. So rather than create a thousand comboboxes in QT, I thought the good idea was to create one set of 50 (ish) and then provide a few button to switch between categories. So when the user selects speed QT, populates the comboboxes with the appropriate options, sets the style sheets and text for the labels etc. So it appears as though a dedicated page exists. Then if the user selects Direction, QT Writes the current index of each box to a dedicated array and then repopulates the boxes, labels etc with the appropriate content. I then do this over and over for the various needs of the system.
All of that seems to work fine. However I am now in a bind where the options provided to navigate to each page have grown. For instance I have forward / backward buttons (like you woudl expect in a set-up wizard), as well as action menus at the top to jump to a page. So now the code is becoming very repetitious. If you select the next button, I write the current values to array, then repopulate. If you jump to the page from anywhere, I look to see where I am, write it to array, and populate the boxes. Thus if I need to change anything I have to make the change in numerous places in the code.
I know that this is not optimal. What I woudl like to do is run a continuous loop as I woudl normally do with Micros in C. So the program can look at a variable in each pass and if it is then it does. I am not however skilled enough to figure this loop out in QT. So my new thought was...
Is it possible to trigger an action or slot with a variable. For example, if the user presses the Next button it triggers a slot for a button that does not exist, so that QT will execute a particular line of Code? Then I can have 1 dedicated section focused on reading and writing boxes, with a bunch of actions that will take me there.
You can make a signal that is triggered with an emit call in your code, so you'd hook up the next button signal of clicked to a slot that does some work and moves on, or directly calls another signal that you've created that triggers a slot elsewhere, or do some work in a lambda triggered by the button press.
I would first load all the ComboBoxes options in a QStringList array (or maybe an array of QList<QLatin1String> lists - for memory saving and code efficiency).
Then I would keep an array of a 1000 integers for current ComboBox indexes.
When the user changes a value in some ComboBox, the currentIndexChanged signal will trigger the corresponding slot (a single slot for all the ComboBoxes would be enough - sender()->objectName() to get the name of the ComboBox which had sent the signal):
void WindowWidget::on_ComboBox_currentIndexChanged(int index)
{
name = sender()->objectName();
/* here change the corresponding integer in the current
indexes array */
}
On Next/Back button push repopulate the ComboBoxes. Also, provide some 'Save' button for saving the ComboBoxes indexes (or trigger the Save slot on some action, i.e. on window close either even on a timer signal).

Conditional commands

I have three main views in my application: A, B and C. Each of these views contain a view called X. Clicking a button in the X view dispatches a FooEvent to the event pool.
I would like to map multiple commands to the FooEvent and execute one of them depending on which main view (A, B or C) is currentry visible. I would have to add an if clause to every command mapped to FooEvent checking if the correct view is visible and I don't like this. Distributing logic across commands makes them hard to manage.
What is the best way to conditionally call commands in the context my application?
Inside X mediator you can create a listener for a FooEvent.
and then based on X parent you dispatch new Event.
Or inside A,B and C you listen for FooEvent, and when you catch it you mediate it from A,B or C mediator to specific command.
The goal is to keep view events inside views, and to mediate new communication further
You can also use Signals

How can fragment pass data to calling fragment

I have an activity with two fragments say F1 and F2. On clicking the list view of F2 , a new fragment is called say F3 (Its single activity multi fragments design).
I have back button on right side of dual pane layout. On hitting this button i need to pass data from fragment F3 to F2, so that F2 views are updated based on data received(something like onActivityForResult for activity to activity interaction).
How can i achieve this?
Fragment class has setTargetFragment(), according to docs:
Optional target for this fragment. This may be used, for example, if
this fragment is being started by another, and when done wants to give
a result back to the first. The target set here is retained across
instances via FragmentManager.putFragment().

Trigger action on completion of drag action

I'm trying to allow items from a QListWidget to be dragged to a "Trash" (A subclassed widget which accepts drops and does nothing with them).
I know that if I setDropAction(Qt.MoveAction), the items I am removing from the source will be automatically deleted. This works correctly.
My problem is that I also need to trigger an action that updates other widgets who depend upon the contents of the source.
It seems to me that the dropEvent happens before any items are actually removed from the source. I'm having a terrible time trying to figure out this problem. I've thought of two possible solutions:
Find a way to embed the references to the actual QListWidgetItems that are being dragged in the event's QMimeData. This would allow me to do the deletions by hand, before I trigger updates.
Figure out how to wait until the source has been automatically cleared, but I can't find any signals that fire when items are removed from a list automatically.
Aha!
The key I was missing was the mimeData method. This method is called when a drag is started, and in it I am passed a list of all files being dragged.
I first built the meta object to be returned, then I deleted the files being dragged from the list, and called the refresh action that I needed.
Here's an example:
def mimeData(self, items):
m = QMimeData()
m.setUrls([QUrl(i.url) for i in items])
# Clean up the list:
[self.files.takeItem(self.files.indexFromItem(i).row()) for i in items]
self._update_meta()
return m

flex how to refresh already created view

How can I refresh view after a certain event?
I have a view which contains multiple groups. I want to show or hide some groups.
onCreationComplete() or initialize() method works only at the beginning of the view creation.
Try invalidateDisplayList() on the view
Let me know if that doesn't do the trick and we'll try some other tricks.
I personally don't like the answer that says to call invalidateDisplayList (sorry no offense Nate nothing personal). I feel it's too vague and doesn't explain what this does under the hood and furthermore you shouldn't have to call it directly in cases such as the one explained in the OPs question. You can simply create booleans that are bindable for each of the groups you'd like to show/hide then in the event handler set those booleans to the appropriate value and if they are bound to the visible and include in layout properties of the containers those containers will internally call invalidateDisplayList after calling set visible and consequently commitProperties.
This is basically what happens under the hood as I understand it: The way this works is values aren't committed or used to update the display until the next frame this way it doesn't get bogged down doing unnecessary layout calculations. So you update the bindable property which fires an event which triggers a notification in the listener (in this case a function that sets the property on your control), that in turn passes along the value to the control which sets an internal flag to update the property and calls invalidateProperties. When it hits the next frame redraw it sees that the properties flag is dirty (true) and then calls commitProperties, this computes/sets the appropriate values (possibly also invalidating then "fixing" the size using invalidateSize() and measure()) and calls invalidateDisplayList, then during the same frame it sees that the display list flag is dirty so it calls updateDisplayList, here it uses the values of the properties to draw appropriately.
You should also be able to achieve this using states, which add or remove children from the display list based on an array of "actions" for each state.

Resources