I have two Rectangles, each with a TapHandler. Rectangle A is the parent of Rectangle B
How can I configure A and B, so that when B is clicked, the EventPoint does not propagate to the onSingleTapped handler of A?
The EventPoint docs suggest to set its accepted property to true:
Setting accepted to true prevents the event from being propagated to Items below the PointerHandler's Item.
However, at the same time the docs state that accepted is a read-only property, which does not make much sense (I guess the documentation is out-of-date or simply wrong).
TestCode:
Rectangle {
id: a
width: 200
height: 200
color: "yellow"
TapHandler {
onSingleTapped: console.log("A tapped")
}
Rectangle {
id: b
color: "blue"
width: 100
height: 100
TapHandler {
onSingleTapped: function(eventPoint) {
// Stop propagation.
eventPoint.accepted = true
console.log("B tapped")
}
}
}
}
UPDATE: Setting the gesturePolicy of B to TapHandler.ReleaseWithinBounds prevents A from receiving the event. Not sure if this really the best solution
For Handlers, the entire event is delivered to each handler; therefore Handlers accept individual points, not the whole event. In general, accepting all points implies accepting the entire event, but it may be that one handler accepts some points while another accepts other points. delivery is not “done” until all the points are accepted.
It looks like setting grabPermissions without a gesturePolicy does not do what's expected .. grab the event and preventing propagation to other items.
Changing Rectnagle b (a's child) TapHandler to have gesturePolicy: TapHandler.ReleaseWithinBounds TapHandler.WithinBounds seems the right way to aaccept, in other words this way it accepts the point, that means the event will not propagate to the TapHandler of the parent Rectangle!
Rectangle {
id: b
z:2
color: "blue"
width: 100
height: 100
TapHandler {
gesturePolicy: TapHandler.ReleaseWithinBounds | TapHandler.WithinBounds
grabPermissions: PointerHandler.CanTakeOverFromAnything | PointerHandler.CanTakeOverFromHandlersOfSameType | PointerHandler.CanTakeOverFromItems
| PointHandler.ApprovesTakeOverByAnything | PointHandler.ApprovesCancellation
onSingleTapped: function(eventPoint) {
// Stop propagation.
eventPoint.accepted = true // this is just a confirmation!
console.log("B tapped")
}
}
}
further from .. narkive interset group
Qt makes a difference between active and passive touch point / pointer grabs. grabPermissions only affect active grabbers. TapHandler is passive with the default gesturePolicy, and active otherwise. That's why you need to change the gesturePolicy in a TapHandler to see any grabPermissions in effect, even the default ones.
Other input handlers don't have this same quirk, but have others. While each handler is simpler than a MouseArea or MultiPointTouchArea as Qt intended, interactions between layered handlers became much more complicated than between layered Area instances. So, for complex input, I'm using an Area instead. Which one depends on whether I'm handling hover or multitouch.
Active and passive grabs: https://doc.qt.io/qt-6/qtquickhandlers-index.html#pointer-grab
TapHandler behavior: https://doc.qt.io/qt-6/qml-qtquick-taphandler.html#details
Yes as the grabPermissions docs say:
This property specifies the permissions when this handler's logic decides to take over the exclusive grab, or when it is asked to approve grab takeover or cancellation by another handler.
"Exclusive" means it's the conventional kind of grab that only one Item or Handler can hold at any given moment. Whereas passive grabs are made for stealth, to deal with the fact that all gestures are ambiguous at the time when the user presses initially: several handlers can take passive grabs to register interest in that point, to monitor mouse or touchpoint movements independently, and then perhaps one of them can decide later to transition to taking the exclusive grab when some condition is met, such that the handler believes the user is initiating a gesture that is relevant to that handler. At the time of the transition, grabPermissions control the negotiation that will occur: which one gets to take over the exclusive grab.
But TapHandler's default gesturePolicy is DragThreshold, and in that case it can detect a tap using only a passive grab, which makes it work independently of other items or handlers. This is meant to be useful for augmenting behavior of other components without interfering with their built-in behavior; but it's not so useful if you want to ensure that only one thing can detect a tap or click. If you want TapHandler to participate in exclusive-grab negotiations (stealing the grab from other items or handlers, and allowing or disallowing the grab to be stolen by another), then you need to set gesturePolicy first, to make it use an exclusive grab. Then, if the TapHandler takes the exclusive grab on press, and the grab is stolen by something else, it will emit canceled rather than tapped.
Sorry it turned out a bit unintuitive: the intention was that gesturePolicy is a designer-friendly property, you just specify the behavior you want and don't worry about grabs. But in practice, it seems to me that we often end up changing gesturePolicy specifically to make TapHandler take an exclusive grab, to not be so stealthy, to participate in the negotations with other components.
If you need to troubleshoot grab-transition scenarios at runtime (which in practice is the first thing to think about whenever mouse or touch behavior is not what you expected), there are several grabbing-related logging categories: qt.pointer.grab qt.quick.handler.grab and qt.quick.pointer.grab. (There are some logging differences between Qt 5 and 6 though.) What I do on Linux is I have a big ~/.config/QtProject/qtlogging.ini file with all logging categories that I've ever cared about, in alphabetical order, mostly commented out (first line begins with # symbol), but those related to event delivery and grabs are often uncommented, since I spend a lot of time trying to fix Qt bugs related to that.
As for setting accepted to true or false on an individual event: that's an old MouseArea pattern, not carried forward into the way that Pointer Handlers are used. There are several problems with it:
QPointerEvent and QEventPoint are stack-allocated Q_GADGET types, not Q_OBJECT. That means they are passed from C++ to QML by value. So setting the accepted property would have no effect, even if we made it a writeable property: you'd be modifying a copy, and the event delivery logic would not see it. When MouseArea lets you do that, it has to populate a special QMouseEvent (QObject) on the fly so that it can be emitted by pointer, just so that you can set that property, and Qt code can see that you set it. (At least since 5.8 those wrapper objects get reused rather than being allocated on-the-fly.)
QML is supposed to be a declarative language. It's not declarative (and not FP) to require you to write a snippet of JS that imperatively sets a property for the sake of its side effect on delivery logic.
QML is supposed to be a designer-friendly language. Newbies should not need to understand what it means to accept an event. (ok perhaps that's really not achieved... nice goal though?)
Accepting a whole event is sensible for mouse but not for touch: if some fingers touch one item and other fingers touch another, you could execute multiple gestures simultaneously (for example you could drag multiple sliders with multiple fingers, if the slider component uses DragHandlers). If accepting the event implies that one item is grabbing all fingers at the same time, that's incompatible with providing the complete event to each item. Because of this, we have to split up QTouchEvents during delivery to Items, which is complex and bad for efficiency. We'd like to be able to stop doing that some day. For now, only Handlers get to see the complete events (all touchpoints, even those that are outside the Item's bounds). This allows things like the margin property to work.
Accepting an event does two things: you are asking to stop propagation, and you are also implicitly asking for an exclusive grab, of the entire event, as you saw it (after the touch-splitting). Basically you are saying "the buck stops here", which is a bit arrogant. (How can one component know for sure, at the time of press, that it's the sole component in the entire application that could possibly care about that gesture?) This is legacy logic that we have to maintain because of all the legacy Items that do event handling that way (MouseArea, Qt Quick Controls, stuff in other Qt modules, lots of third-party components). In the future it's probably better to separate grabbing from control of propagation. This is part of why passive grabs exist too: handlers must be able to act cooperatively, to deal with ambiguity, so they generally should avoid stopping propagation, to allow other handlers to also see the same events. Only when a handler is sure that a gesture has really started should it attempt to take the exclusive grab.
Related
I am subclassing QDoubleSpinBox to add some features (like incrementing the value based on the location of the cursor in the lineedit) and to change some features I find annoying. One of the latter is that intermediate values are emitted: e.g. if you want to enter the value 323 it will emit 3 then 32 then finally 323. I'd like to set it to only emit on entry (i.e. only actually change value on entry).
Anyway, I can't figure out how to capture these intermediate edits. I overrode setValue to see if I could stop it there somehow, but it apparently isn't called (or at least my override isn't). I'm not sure how the value is actually getting set while editing in line edit.
More generally, the logic of this box escapes me. Is there some documentation that explains e.g. "if you type a digit into the lineedit then this series of routines is called... while if you hit the up arrow, this series of routines is called?"
In case it matters, I'm using PyQt5
EDIT: Here is another case in which having access to this is important. Say I want to implement an undo/redo structure for the box. The only way I can think of to get access to the changed values is to connect to the valueChanged signal. But if I'm subclassing the box it seems a little convoluted to listen for a signal rather than just watch the value change 'internally' Or am I missing something here?
You could use the following signal:
void QAbstractSpinBox::editingFinished() [signal]
This signal is emitted editing is finished. This happens when the spinbox loses focus and when enter is pressed.
based on the documentation of QAbstractSpinBox:
http://qt-project.org/doc/qt-5.1/qtwidgets/qabstractspinbox.html#editingFinished
There is nothing that combines the arrow based changes and the editingFinished changes.
My use case was to let the user enter the value without getting the signal on each new digit, while still making ↑, ↓, Page Up, Page Down keys and arrow buttons work as usual, emitting the signal on each activation.
QAbstractSpinBox::editingFinished signal doesn't provide this functionality: it's only ever emitted when focus is lost or Return/Enter is pressed.
What does work exactly as I need is the keyboardTracking property of QAbstractSpinBox. If it's true (the default), the spinbox emits valueChanged on each digit typed. If you set it to false, it behaves exactly as I described in the beginning of this answer.
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.
I am trying to get my Windows State Machine workflow to communicate with end users. The general pattern I am trying to implement within a StateActivity is:
StateInitializationActivity: Send a message to user requesting an answer to a question (e.g. "Do you approve this document?"), together with the context for...
...EventDrivenActivity: Deal with answer sent by user
StateFinalizationActivity: Cancel message (e.g. document is withdrawn and no longer needs approval)
This all works fine if the StateActivity is a "Leaf State" (i.e. has no child states). However, it does not work if I want to use recursive composition of states. For non-leaf states, StateInitialization and StateFinalization do not run (I confirmed this behaviour by using Reflector to inspect the StateActivity source code). The EventDrivenActivity is still listening, but the end user doesn't know what's going on.
For StateInitialization, I thought that one way to work around this would be to replace it with an EventDrivenActivity and a zero-delay timer. I'm stuck with what to do about StateFinalization.
So - does anyone have any ideas about how to get a State Finalization Activity to always run, even for non-leaf states?
Its unfortunate that the structure of "nested states" is one of a "parent" containing "children", the designer UI re-enforces this concept. Hence its quite natural and intuative to think the way you are thinking. Its unfortunate because its wrong.
The true relationship is one of "General" -> "Specific". Its in effect a hierachical class structure. Consider a much more familar such relationship:-
public class MySuperClass
{
public MySuperClass(object parameter) { }
protected void DoSomething() { }
}
public class MySubClass : MySuperClass
{
protected void DoSomethingElse() { }
}
Here MySubClass inherits DoSomething from SuperClass. The above though is broken because the SuperClass doesn't have a default constructor. Also parameterised constructor of SuperClass is not inherited by SubClass. In fact logically a sub-class never inherits the constructors (or destructors) of the super-class. (Yes there is some magic wiring up default constructors but thats more sugar than substance).
Similarly the relationship between StateAcivities contained with another StateActivity is actually that the contained activity is a specialisation of the container. Each contained activity inherits the set of event driven activities of the container. However, each contained StateActivity is a first class discrete state in the workflow same as any other state.
The containing activity actual becomes an abstract, it can not be transitioned to and importantly there is no real concept of transition to a state "inside" another state. By extension then there is no concept of leaving such an outer state either. As a result there is no initialization or finalization of the containing StateActivity.
A quirk of the designer allows you to add a StateInitialization and StateFinalization then add StateActivities to a state. If you try it the other way round the designer won't let you because it knows the Initialization and Finalization will never be run.
I realise this doesn't actually answer your question and I'm loath to say in this case "It can't be done" but if it can it will be a little hacky.
OK, so here’s what I decided to do in the end. I created a custom tracking service which looks for activity events corresponding to entering or leaving the states which are involved in communication with end users. This service enters decisions for the user into a database when the state is entered and removes them when the state is left. The user can query the database to see what decisions the workflow is waiting on. The workflow listens for user responses using a ReceiveActivity in an EventDrivenActivity. This also works for decisions in parent ‘superstates’. This might not be exactly what a "Tracking Service" is meant to be for, but it seems to work
I've thought of another way of solving the problem. Originally, I had in mind that for communications I would use the WCF-integrated SendActivity and ReceiveActivity provided in WF 3.5.
However, in the end I came to the conclusion that it's easier to ignore these activities and implement your own IEventActivity with a local service. IEventActivity.Subscribe can be used to indicate to users that there is a question for them to answer and IEventActivity.Unsubscribe can be used to cancel the question. This means that separate activities in the State's inialization and finalization blocks are not required. The message routing is done manually using workflow queues and the user's response is added to the queue with appropriate name. I used Guid's for the queue names, and these are passed to the user during the IEventActivity.Subscribe call.
I used the 'File System Watcher' example in MSDN to work out how to do this.
I also found this article very insructive: http://www.infoq.com/articles/lublinksy-workqueue-mgr
This may be a bit of a beginners question, but I can't for the life of me figure it out.
I'm using flex to develop a GUI for a large project, specifically a status bar along the bottom. Within my StatusBar class is a ProgressBar, which other classes doing work can tell to update(change bar completion and label) as they progress. The problem I'm encountering is that flex won't update whats shown on the screen until it's too late, for example
ProgressBar initialized, 0% done
some class sets the ProgressBar to be 12% done
some class does some work
some class sets the ProgressBar to be 56% done
Whats happening is the 12% done is never displaying, it just hangs at 0% during the work, then skips right to 56% done. I've tried to understand the lifecycle of a flex component (invalidation and validation), and I think I understand it and am applying it correctly, but it's not working at all. I need to tell flex to redraw my StatusBar (or at least the ProgressBar within) after some class sets it to be 12% done, but before some class starts doing its work. How do I do this?
As mentioned in other answers, the flash player is single threaded, if you don't break up your work into discrete chunks that can be executed in separate "frames", you're going to see jumps and stutters in the ui, which is effectively what you're seeing.
If you really must see that 12% message, then it's not enough to invalidate the display list, as the display list isn't getting a chance to update until after the 56% work has completed, you must explicitly interrupt the natural event cycle with a call to validateNow() after your message has been set.
This however is not the best way to do things if performance is of concern. You might get by with judicial usage of callLater() to schedule each chunk of work in turn, as this will allow the player to potentially complete a frame cycle (and update the display list) before attempting the next step in your process.
Glenn,
That is not at all how the threading in Flex works whatsoever. Like many UIs it has a message pump on the main UI thread (they do it in frames). When you call callLater() it places the passed in function pointer at the end of the message pump queue (on the next frame) and returns immediately. The function then gets called when the message pump has finished processing all of the messages prior (like mouse clicks).
The issue is that as the property change causes UI events to be triggered, they then place their own messages on the pump which now comes after your method call that you placed there from callLater().
Flex does have multiple threads but they are there for Adobe's own reasons and therefore are not user accessible. I don't know if there is a way to guarantee that a UI update will occur at a specific point, but an option is to call callLater a number of times until the operation occurs. Start off with a small number and increase until the number of iterations produces the result you want. Example:
// Change this to a number that works... it will probably be over 1, depending on what you're doing.
private const TOTAL_CALL_COUNT:int = 5;
private var _timesCalled:int = 0;
//----------------------------------------------------------------
private function set Progress( progress:int ):void
{
progressBar.value = progress;
DoNextFunction();
}
//----------------------------------------------------------------
private function DoNextFunction():void
{
if( _timesCalled >= TOTAL_CALL_COUNT )
{
_timesCalled = 0;
Function();
}
else
{
_timesCalled++;
callLater( DoNextFunction );
}
}
Try calling invalidateDisplayList() after each changes to your progress bar. Something like :
Class StatusBar
{
public function set progress(value:uint):void
{
progressBar.value = value;
progressBar.invalidateDisplayList();
}
}
Flex has an invalidation cycle that avoid screen redrawing everytime a property changes. As an example, if a property's value changes 3 times in a single frame, it will render only with the last value set. You can force a component to be redrawn by calling invidateDisplayList() which means updateDisplayList will be immediatly executed instead of waiting the next frame.
Actionscript in Flash player, like Javascript in the browser, is pseudo-multithreaded. That is, they're single threaded, but they have multiple execution stacks. This means you can't "sleep" in a particular thread, but you can spawn a new execution stack that gets deferred until a later time. The flex way of doing this is the "callLater" function. You can also use the setTimeout/setInterval functions. Or you can use a timer object built into the flash player. Or even "ENTER_FRAME" event listener. All of these will essentially allow you to do what you need, if I'm correct about the cause of your problems.
It sounds like you have one "thread" doing most of your work, never stopping to allow other execution stacks (threads*) to run.
The problem could be what PeZ is saying, but if that doesn't help, you might want to try some deferred calls for worker classes. So your process might look like this now:
Progress initialized.
Do some work.
Update progress bar to 12. (invalidate display list)
setTimeout(doMoreWork, 100);
Update progress bar to 52.
(if your worker is a UIcomponent, you can use uicomp.callLater(...), otherwise, you need to use setTimeout/timers/enter_frame for pure AS3 classes).
Sometimes its necessary set to zero before assign another value.
progressBar.setProgress(0, progressBar.maximum);
progressBar.setProgress(newValue, progressBar.maximum);
I'm using Flash Builder 4.6 and I also have a problem for the display of my progress bar. I open a new window where I start a new multiloader class (39 Mo of content). The new window is opened in background and the main window display a progress bar until the multiloader class has finished his work. However the opening window is blocking the animation of my main window. I know it's not the multiloader class cause I saw it running correctly.
But I will try to find some new ways of doing it.
The main purpose of my post is the complexity adobe has build around flash.
When you seek ressources for your own application or answers for your questions, it's a real pain to find the good ressource. There is a total mix up (at adobe side and at user side) between AS3, Flex, Flash CS, Flash Builder, AiR, ... If you try to develop in AS3, you will find that some examples won't work for you because it is not implemented in your SDK. You have more and more forums giving you the "best practice" or ironic answers based on experiences on different developping platform.
By example, just here above, I see progressBar.value = value; With my experience, I can say that in Flash Builder 4.6, this property is read-only. But It might be a custom class made by the user but who can tell.
Im wondering how to implement undo redo functionality with a TextArea. I already have an undoredo framework functionality working, now I have two questions.
When do I start/stop a new undo/redo command, eg when a user hits undo, how far back do I go.
How do I implement this(1.) in a normal TextArea
My thinking:
I thinking that I should create a new undo command, when anything but a alphanumber+space is hit. To do this I would use the keyDown event and test if the key is alpha num if it is not I will reset the command.
Sound good?
Listening for keydown events would miss any text editing that user does with the mouse (cut/copy/paste).
I think a better approach would be to listen for 'change' event on the control (which fires whenever the content changes through user input), and just push the full content of the control (its 'text' or 'htmlText' attribute) with every change event into a undo-buffer (an Array of Strings). I assume that the memory usage is not an issue (it probably isn't, depending on the expected size of the controls content and number of undo levels).
This way, you implement undo/redo just by copying the corresponding control state (moving up and down through array, basically) in the undo buffer back into the control.
The 'proper' approach would be to track the actual edits, and would be condsiderably more complicated.
1.When do I start/stop a new undo/redo command, eg when a user hits undo, how far back do I go.
Do you think your users will need to undo multiple steps? If so, then you may want to have a history (e.g. Paint .NET) and allow infinite undo-s. Otherwise, just remember the most recently performed action.
1.) You should listen for the Event.CHANGE event on the TextField and create a history step each time the event is fired. A history step consists in your case of two values: old and new.
Old is the value of the TextField before change, new is its value after the change.
2.) Your history is a sequence of actions or you can use the Memento Pattern. I think actions are much easier to use. A history action has two methods, undo() and redo(). So in undo() you have to say textField.text = oldContent and in the redo() method you say textField.text = newContent. Your history will also need a pointer to the current action.
3.) To make it a little bit better. You should not listen only for Event.CHANGE but instead listen for the first CHANGE and then the next FOCUS_OUT for that TextField. In that case, a history step is only created once I stop editing the TextField. But it depends on your TextField and how you want to distribute history steps. A multiline TextField should not create a history step only on FOCUS_OUT :)