I have Sprites that I want to have move around when I click and hold them and stop when I release them. I have methods that add Event listeners to the Sprites:
public function layOutEventListeners():void
{
var addSpriteEventListener:Function =
function(spr:Dictionary, index:int, vector:Vector.<Dictionary>)
{
spr["sprite"].addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
spr["sprite"].addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
gridVec.forEach(addSpriteEventListener);
}`
and methods to handle the events:
public function mouseDownHandler(me:MouseEvent):void
{
trace(me.target.toString());
trace(me.currentTarget.toString());
this.drawSprite(me.target);
this.growByTwo(me.target);
me.stopImmediatePropagation();
me.currentTarget.startDrag(me);
}
public function mouseUpHandler(me:MouseEvent):void
{
trace(me.target.toString());
trace(me.currentTarget.toString());
me.stopImmediatePropagation();
this.originalSize(me.target);
me.currentTarget.stopDrag();
}`
My problem is: when I click on the Sprites, as soon as I move the cursor, the Sprite's registration point snaps to the cursor, and when I release the mouse the Sprite doesn't stop following the cursor. I initially thought it was a problem with pixel collision. I thought the cursor wasn't touching anything on MOUSE_UP, but that proved to be false after I experimented. I even replicated the exact same Event adding and handling methods by starting another project and found that I wasn't having this problem. The test Sprite was simply dragging and dropping like usual, not snapping to the registration point, and being dragged by the point I clicked.
The only difference I can see, and also my only suspicion, is that the Sprites in my original code are being added to a Sprite, which is then being added to the stage, whereas the Sprite in the test project is being added to the root DisplayObject. I'm thinking that somehow the Event propagating down to the container Sprite and dragging and dropping that without dropping the other Sprite. The weird snapping I'm seeing might be the cursor snapping to the object behind the other sprite. Another important thing: when I drop a Sprite on top of another Sprite, that Sprite stops moving like I want it to, but still trails the registration point.
Regardless, I'm really stumped and I really don't know that I'm running over. Any ideas?
This is usually because sometimes the mouse is not over the clip when MOUSE_UP occurs, either because of other clips getting in the way or maybe the player is not refreshing the stage fast enough, etc...
I'm not sure this is your case, but either way it is often recommended to assign the MOUSE_UP event to the stage, so you can safely assure it is always triggered. Make sure to remove the listener on the mouseUp handler though ;)
spr["sprite"].addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
public function mouseDownHandler(me:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
public function mouseUpHandler(me:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
The down side is that you lose your clip reference on mouseUp, but you can create a reference by hand on mouseDown, or do the whole thing internally (within the sprite's code).
Related
I have created my own custom QTreeWidget, and overrided the mouseMoveEvent.
It looks something like the below,
MyTreeWidget::mouseMoveEvent(QMouseEvent* aEvent)
{
QTreeWidget::mouseMoveEvent(aEvent); // This line causes the issue
// My logic
}
I'm getting a hovering effect on the treewidget, when mouseMove happens (This is not expected). I have also set the focus (Qt::WA_MacShowFocusRect) to be false. But still, see the hover effect when I move the mouse in and out. I found out this is because of the line - QTreeWidget::mouseMoveEvent(aEvent), which calls the base class implementation which sets the hover. But, I need that to be called to support reorder of tree items, when mouseTracking is enabled.
I don't find any way to unset the hover events. Any help around this?
I have a QGLWidget that renders an OpenGL scene inside a Qt application. I would like to add some other translucent Qt widgets that are overlaid on top of the QGLWidget. This is more difficult than with standard widgets since the OpenGL drawing context is unknown to Qt's painter classes. So, if I just do the obvious thing and place a transparent toolbar on top of the QGLWidget for instance, the transparent part of the toolbar instead renders black (it doesn't have access to the OpenGL frame buffer when painting).
It seems that the recommended way for handling this sort of thing is to overpaint the 2D content after drawing the OpenGL scene. The linked example seems very straightforward, as long as you're just drawing simple shapes. Instead, what I would like to do is to defer the painting of some child QWidget objects to be done inside the paint event for the QGLWidget.
So, my problem boils down to this:
Prevent the overlay QWidgets from painting in the normal, 2D context.
In the paint event handler for the QGLWidget, paint the overlays after painting the 3D scene that makes up the background.
The second item on this list seems to be simple: I can use QWidget::render() inside the QGLWidget's paint event to draw the desired widgets on top of the viewport. This works just fine.
The first item is more tricky: I need a way to prevent the widgets from painting during the normal course of events and only paint them in the QGLWidget's paint handler. One obvious way to do this is to hide the overlays using QWidget::hide(). This does allow me to paint the widgets atop the OpenGL scene as I would like. However, since the widgets are hidden, they do not respond to mouse or keyboard events. As an example, I'm using a QToolBar with a few buttons on it, and the toolbar is painted properly, but is non-functional (none of the buttons respond to clicks). So, if going down this path, it seems that I would need a way to force the widget to still respond to events even though it is hidden.
Another approach that I've tried is to intercept the QToolBar's paint event using an event filter, with the goal of preventing the toolbar from painting itself. However, the toolbar is still rendered; I'm assuming that this is because the various buttons on the toolbar are child widgets that are still painted, even if I intercept the parent's paint event.
Any ideas on a way that I could accomplish my goal?
I don't understand your issue completely, but I'll try to answer the question stated in the title. You should use event filters. Install an event filter using widget->installEventFilter(object), where widget is a widget you want to block painting, and object is an object of any of your QObject-derived classes. Reimplement eventFilter of this class:
bool MyClass::eventFilter(QObject* object, QEvent* event) {
if (event->type() == QEvent::Paint) { return true; }
return false;
}
When you return true from your eventFilter, the event is filtered and paint doesn't occur.
You can also try to use widget->setUpdatesEnabled(false) to temporarily disable painting. Don't forget to re-enable it when you're done.
I have a TextArea that shows the conversation from selected chat room. For valueCommit event I use: verticalScrollPosition = maxVerticalScrollPosition; And it works fine scrolling text to the bottom. However in one case it doesn't work as expected. There's verylittle text, so TextArea has no scrollbar and then I put a lot of text and a scrollbar is necessary. The text is scrolled almost to the bottom (still a few lines need to be scrolled down). I am pretty sure it gets maxVerticalScrollPosition as if there was no scrollbar. So the question is how can I wait with updating verticalScrollPosition with respect to TextArea's new size (that is now with a scrollbar). I tried calling validateSize and other methods that start with 'validate' but unfortunately with no luck. I also tried the old trick of putting caret at the end of text. So the TextArea's scrollbar makes a difference when getting maxVerticalScrollPosition and I need to update verticalScrollPosition once all measurements are done.
I forgot to mention. I use htmlText.
In the comments of the answer you accepted you mentioned a more elegant solution. Yeah, a timer probably isn't the best option -- you have eventListener cleanup if you remove the component from the stage; if you use the component more than once, you have another timer instance; etc., etc.
If you don't have a lot of post-commit-property actions, the quickest solution would be a call later on the setter of text or htmlText
override public function set text(value:String):void
{
super.text = value;
callLater( scrollToEndAfterTextCommitted );
}
protected function scrollToEndAfterTextCommitted():void
{
this.verticalScrollPosition = this.maxVerticalScrollPosition;
}
I hope that helps.
Best of luck!
Assuming the issue is fixed after you add additional text again, you could probably get by using a Timer, or a call to setTimeout and have the verticalScrollPosition = maxVerticalScrollPosition called a fraction of a second later and see if that fixes it.
It seem when I trying to drag the bordercontainer to move along x-axis position on mouse down. It appear to move stable but became jerky when I drag a little faster.
Any way to get bordercontainer move with smooth motion?
private function mDownHandler(event:MouseEvent):void {
gMouseX = event.localX;
borderCntr.addEventListener(MouseEvent.MOUSE_MOVE, mMoveHandler);
}
private function mMoveHandler(event:MouseEvent):void {
borderCntr.x = int(event.localX)-gMouseX;
}
are you targeting mobile devices? MouseEvent.MOUSE_MOVE is quite intensive for mobile devices since it calls many more times faster than the framerate. it's not optimized nor recommended to use MouseEvent.MOUSE_MOVE for projects with mobile deployment targets.
instead, create your own moving logic by employing either the stageX and stageY properties or startDrag() and stopDrag() functions with an Event.ENTER_FRAME event.
1) You shouldn't use local coordinates in your mMoveHandler, because it's coordinates of mouse inside borderCntr - it simply couldn't work as you wish to. Use parent's or top level application's mouseX or simply event.stageX.
2) Don't add MouseEvent.MOUSE_MOVE listener to borderCntr. When you will make very quick movement and mouse will walk outside borderCntr, you simply won't recieve move events anymore. Instead listen to parent or stage or top level application (again), the one that would not loose mouse.
When a Flex component moves directly, so that its x and y properties change, then a "move" event is dispatched on the component. That's all fine.
However, a component may also move as a result of its parent component moving — or its parent moving, and so on. Now when a parent component moves, its children just "move along" without any properties changing or move events being dispatched on the children. Still, the children are moving on the screen. So how can you detect this kind of generalized movement?
One workaround is to capture all move events in the application:
Application.application.addEventListener
(MoveEvent.MOVE, handleMove, true, 0, true);
The third argument is required because move events do not bubble, and so instead have to be captured. The fourth argument is unimportant, and the fifth argument turns on weak references, which is a good idea in this case because we are creating a global reference from Application.application to handleMove — a recipe for memory leaks.
Of course, this will fire too often (once each time anything whatsoever in the application moves), and in a large application could lead to performance problems. If you know that there is some component higher up in the hierarchy that’s sure to stay still, you can put the listener at that point instead of globally, which could reduce the problem.
Still, it would be nice to have a cleaner way to solve this.
Well, you've already suggested the most general solution, but I think it's possible for the child to go through parents/grandparents until it reaches one that is stationary (set by some dynamic property you set), at least this would save you some trouble in figuring out which parent handles which child.
private function addHandlerToStationaryParent(handler:function):void
{
var currentParent:DisplayObjectContainer = parent;
while(currentParent != null)
{
if(currentParent["stationary"] == true)
{
currentParent.addEventListener(MoveEvent.MOVE, handler);
return;
}
}
}
I guess it would be your preference as to whether or not this would be a better solution.