I am trying to connect to the mouse-enter event of QGraphicsItems that are placed onto a QGraphicsScene and visualized through a QGraphicsView. From what I understand, the method to override for this is dragEnterEvent in a class derived from QGraphicsItem (or one of it's subclasses). My attempt looks like this:
class StaPoly(QtGui.QGraphicsPolygonItem):
def __init__(self,*args):
QtGui.QGraphicsPolygonItem.__init__(self,*args)
self.setAcceptDrops(True)
def dragEnterEvent(self,event):
print "Enter!"
...
def draw(self):
p = self.parent
self.group = QtGui.QGraphicsItemGroup(scene=p.scene)
...
for xpix in lons:
poly = QtGui.QPolygonF()
poly << QtCore.QPointF(xpix-symw,ypix)
poly << QtCore.QPointF(xpix,ypix+symh)
poly << QtCore.QPointF(xpix+symw,ypix)
poly << QtCore.QPointF(xpix,ypix-symh)
item = StaPoly(poly)
item.setPen(QtGui.QColor(color))
item.setBrush(QtGui.QColor(color))
self.group.addToGroup(item)
I hope the above snippets make it clear what I am trying to do. Note that the display is generated exactly as I desire, no issue there - however the polygons that get drawn are not responding to the enter-event - I am not seeing any evidence that dragEnterEvent() is being called.
The (partial) solution was this:
self.group.setHandlesChildEvents(False)
This ensures that individual items handle their own events, it seems that before the group was capturing them.
I still have a problem in that my GraphicsView overrides the mouseMoveEvent, and when enabled, no events get propagated to scene items.
EDIT: And it seems the solution to this second problem was to call the base class mouseMoveEvent handler from the Views mouseMoveEvent handler e.g.
def mouseMoveEvent(self,event):
QtGui.QGraphicsView.mouseMoveEvent(self, event)
Related
I have a problem with a code in the Game Maker program
I make a little game that has a path that the enemies walk on and put heroes on his side and when the enemy approaches him he turns to him and he shoots him
I am using this code
var ex, ey;
ex = instance_nearest(x, y, enemy).x;
ey = instance_nearest(x, y, enemy).y;
if point_distance(x, y, ex, ey) < 150
{
image_angle = point_direction(x, y, enemy.x, enemy.y);
}
The code works well, but the problem is that my heroes only go to the first enemy when they come close to them and do not go to the rest even when the first enemy is out of range
What is the solution, please
Photo for illustration
Heroes ignore the nearby enemy and only head for the first enemy to appear in the game
You are checking the correct enemy but not pointing at the correct enemy. Store the found instance ID instead, and use it for all:
var e;
e = instance_nearest(x, y, enemy);
if (e != noone) { // wouldn't want to crash when you run out of enemies
if (point_distance(x, y, e.x, e.y) < 150) {
image_angle = point_direction(x, y, e.x, e.y);
}
}
I think the answer gave by YellowAfterlife solved the problem. But not sure if the reason of the problem was clear, then I want to complement by explain that the problem happened because the code in "point_direction" is referencing the object instead of the instance.
The object is the template that the created instance is based of, if you want to manipulate or get information you should reference the instance. If you only have one instance of that object, it will work referencing the object directly, but after more were created, it will return the index of only one of them (maybe the first created).
About instances: every object that you drag to the room will became an instance of that object or when you create an instance from the code, like calling "instance_create_layer(x, y, "instance_layer", obj_Bullet)", this function will return the reference/index of the new instance created.
When the function "instance_nearest" is called it receives the player instance position (x and y) and the object of the instances that you want to check if it's near to the player, for example, the enemy object. The function will check all instances that was created from the informed object and will returns the index/reference of the instance nearest to the player. In the original code when calling the point_direction, was used the object enemy instead of the instance returned by instance_nearest function.
The object will always return the same index of some instance, causing the problem reported, that the player instance always point to the same enemy instance (coincidentally, the first instance created)
You can use the object if want to manipulate all instances at once, like this: "with(o_player) y++;". This code will make all instances of that object move down together.
You could use something like collision_circle_list(...).
This function will get you a list of all objects that collide within that circle and you can iterate through them to find which is closest, furthest, etc.
Resource:
https://docs2.yoyogames.com/source/_build/3_scripting/4_gml_reference/movement%20and%20collisions/collisions/collision_circle_list.html
I'm wandering if this is the optimal way of doing it with ScalaFx: A GUI is composed of bunch of nodes, to which I suck content from a SQL-DB. Main Pane is a FlowPane populated with few hundred elements. Each element is composed of four level hierarchy (see numbers describing the levels):
1 2 3 4
VBox -+-> VBox ---> StackPane -+-> ImageView
+-> Label +-> Rectangle
As far as I have experienced the I can access the nodes and their attributes in different levels. Ie. I can give user feedback by changing the Rectangle color below the ImageView Node as the compound element is chosen by mouse click or by ContextMenu.
I could access the Rectangle attributes directly, but it is easy to make mistakes as the list references children.get(0) are directly dependent from order of the children as the nodes are positioned in parent.
val lvone = vbnode.children // VBox (main)
val lvtwo = lvone.get(0) // VBox
val lvthree = lvtwo.asInstanceOf[javafx.scene.layout.VBox].children.get(0) // StackPane
val lvfour = lvthree.asInstanceOf[javafx.scene.layout.StackPane].children.get(0) // Rectangle
if (lvfour.isInstanceOf[javafx.scene.shape.Rectangle]) lvfour.asInstanceOf[javafx.scene.shape.Rectangle].style = "-fx-fill: #a001fc;"
println("FOUR IS:"+lvfour.getClass)
Here's sample to demonstrate the "safer" access to the elements in node hierarchy (node hierarchy creation is in rather annoying structure of code, so it is not included):
val levelone = vbnode.children
println("LV1 Node userData:"+vbnode.userData) // my database reference for the main / container element
println("LV1 Parent children class:"+levelone.get(0).getClass) // class javafx.scene.layout.VBox
for (leveltwo <- levelone) {
println("LV2 Children Class:"+leveltwo.getClass)
println("LV2 Children Class Simple Name:"+leveltwo.getClass.getSimpleName) // VBox
if (leveltwo.getClass.getSimpleName == "VBox") {
leveltwo.style = "-fx-border-width: 4px;" +
"-fx-border-color: blue yellow blue yellow;"
for (levelthree <- leveltwo.asInstanceOf[javafx.scene.layout.VBox].children) {
println("LV3 children:"+levelthree.getClass.getName)
if (levelthree.getClass.getSimpleName == "StackPane") {
for (levelfour <- levelthree.asInstanceOf[javafx.scene.layout.StackPane].children) {
println("LV4 children:"+levelfour.getClass.getName)
if (levelfour.getClass.getSimpleName == "Rectangle") {
if (levelfour.isInstanceOf[javafx.scene.shape.Rectangle]) println("Rectangle instance confirmed")
println("LV4 Found a Rectangle")
println("original -fx-fill / CSS:"+ levelfour.asInstanceOf[javafx.scene.shape.Rectangle].style)
levelfour.asInstanceOf[javafx.scene.shape.Rectangle].style = "-fx-fill: #a001fc;"
} // end if
} // end for levelfour
} // end if
} // end for levelthree
} // end if
} // end for leveltwo
Questions:
Is there smarter way to do the type casting of node types, since only javafx API based references are acceptable (BTW I'm using ScalaIDE)? Options I am using are:
1- simple / shortcut way: evaluation by using leveltwo.getClass.getSimpleName == "VBox" , which is the shortcut from API jungle. But is it efficient and safe?
2- cluttering way by using probably the by the book style:
if (levelfour.isInstanceOf[javafx.scene.shape.Rectangle])
Other question: Now in reference to the fully qualified reference based on javafx ie. javafx.scene.shape.Rectangle, I would like to use scala reference instead, but I get an error which enforces me to adopt the javafx based reference. Not a big deal as I can use javafx reference, but I wander if there is scalafx based option?
Happy to get constructive feedback.
If I understand you correctly, you seem to be wanting to navigate the nodes of a sub-scene (that belongs to a higher-level UI element construct) in order to change the appearance of some of the nodes within it. Do I have that right?
You raise a number of different issues, all within the one question, so I'll do my best to address them all. As a result, this is going to be a long answer, so please bear with me. BTW, In future, it would help if you ask one question for each issue. ;-)
Firstly, I'm going to take your problem at face value: that you need to browse through a scene in order to identify a Rectangle instance and change its style. (I note that your safe version also changes the style of the second VBox, but I'm going to ignore that for the sake of simplicity.) This is a reasonable course of action if you have little to no control over the structure of each element's UI. (If you directly control this structure, there are far better mechanisms, which I'll come to later.)
At this point, it might be worth expanding on the relationship between ScalaFX and JavaFX. The former is little more than a set of wrappers for the latter, to give the library a Scala flavor. In general, it works like this: the ScalaFX version of a UI class takes a corresponding JavaFX class instance as an argument; it then applies Scala-like operations to it. To simplify things, there are implicit conversions between the ScalaFX and JavaFX instances, so that it (mostly) appears to work by magic. However, to enable this latter feature, you must add the following import to each of your source files that reference ScalaFX:
import sclafx.Includes._
For example, if JavaFX has a javafx.Thing (it doesn't), with setSize and getSize accessor methods, then the ScalaFX version would look like this:
package scalafx
import javafx.{Thing => JThing} // Rename to avoid confusion with ScalaFX Thing.
// ScalaFX wrapper for a Thing.
class Thing(val delegate: JThing) {
// Axilliary default constructor. Let's assume a JThing also has a default
// constructor.
//
// Creates a JavaFX Thing when we don't have one available.
def this() = this(new JThing)
// Scala-style size getter method.
def size: Int = delegate.getSize
// Scala-style size setter method. Allows, say, "size = 5" in your code.
def size_=(newSize: Int): Unit = delegate.setSize(newSize)
// Etc.
}
// Companion with implicit conversions. (The real implementation is slightly
// different.)
object Thing {
// Convert a JavaFX Thing instance to a ScalaFX Thing instance.
implicit def jfxThing2sfx(jThing: JThing): Thing = new Thing(jThing)
// Convert a ScalaFX Thing instance to a JavaFX Thing instance.
implicit def sfxThing2jfx(thing: Thing): JThing = thing.delegate
}
So, quite a lot of work for very little gain, in all honesty (although ScalaFX does simplify property binding and application initialization). Still, I hope you can follow me here. However, this allows you to write code like the following:
import javafx.scene.shape.{Rectangle => JRectangle} // Avoid ambiguity
import scalafx.Includes._
import scalafx.scene.shape.Rectangle
// ...
val jfxRect: JRectangle = new JRectangle()
val sfxRect: Rectangle = jfxRect // Implicit conversion to ScalaFX rect.
val jfxRect2: JRectangle = sfxRect // Implicit conversion to JavaFX rect.
// ...
Next, we come to type checking and casting. In Scala, it's more idiomatic to use pattern matching instead of isInstanceOf[A] and asInstanceOf[A] (both of which are frowned upon).
For example, say you have a Node and you want to see if it is actually a Rectangle (since the latter is a sub-class of the former). In the style of your example, you might write something like the following:
def changeStyleIfRectangle(n: Node): Unit = {
if(n.isInstanceOf[Rectangle]) {
val r = n.asInstanceOf[Rectangle]
r.style = "-fx-fill: #a001fc;"
}
else println("DEBUG: It wasn't a rectangle.")
}
The more idiomatic Scala version of the same code would look like this:
def changeStyleIfRectangle(n: Node): Unit = n match {
case r: Rectangle => r.style = "-fx-fill: #a001fc;"
case _ => println("DEBUG: It wasn't a rectangle.")
}
This may seem a little finicky, but it tends to result in simpler, cleaner code, as I hope you'll see. In particular, note that case r: Rectangle only matches if that is the real type of n, and it then casts n to r as a Rectangle.
BTW, I would expect that comparing types is more efficient than getting the name of the class, via getClass.getSimpleName and comparing to a string, and there's less chance of error. (For example, if you mistype the class name of the string you're comparing to, e.g. "Vbox", instead of "VBox", then this will not result in a compiler error, and the match will always fail.)
As you point out, your direct approach to identifying the Rectangle is limited by the fact that it requires a very specific scene structure. If you change how each element is represented, then you must change your code accordingly, or you'll get a bunch of exceptions.
So let's move on to your safe approach. Clearly, it's going to be a lot slower and less efficient than the direct approach, but it still relies upon the structure of the scene, even if it's less sensitive to the order in which the children are added at each level of hierarchy. If we change the hierarchy, it will likely stop working.
Here's an alternative approach that uses the class hierarchy of the library to assist us. In a JavaFX scene, everything is a Node. Furthermore, nodes that have children (such as VBox and StackPane) are subclasses of Pane as well. We'll use a recursive function to browse the elements below a specified starting Node instance: every Rectangle it encounters will have its style changed.
(BTW, in this particular case, there are some issues with implicit conversions, which makes a pure ScalaFX solution a little cumbersome, so I'm going to match directly on the JavaFX versions of the classes instead, renamed to avoid any ambiguity with the equivalent ScalaFX types. The implicit conversions will work fine when calling this function.)
import javafx.scene.{Node => JNode}
import javafx.scene.layout.{Pane => JPane}
import javafx.scene.shape.{Rectangle => JRectangle}
import scala.collection.JavaConverters._
import scalafx.Includes._
// ...
// Change the style of any rectangles at or below starting node.
def setRectStyle(node: JNode): Unit = node match {
// If this node is a Rectangle, then change its style.
case r: JRectangle => r.style = "-fx-fill: #a001fc;"
// If the node is a sub-class of Pane (such as a VBox or a StackPane), then it
// will have children, so apply the function recursively to each child node.
//
// The observable list of children is first converted to a Scala list to simplify
// matters. This requires the JavaConverters import above.
case p: JPane => p.children.asScala.foreach(setRectStyle)
// Otherwise, just ignore this particular node.
case _ =>
}
// ...
A quick few observations on this function:
You can now use any hierarchy of UI nodes that you like, however, if you have more than one Rectangle node, it will change the style of all of them. If this doesn't work for you, you could add code to check other attributes of each Rectangle to determine which one to modify.
The asScala method is used to convert the children of the Pane node to a Scala sequence, so we can then use the foreach higher-order function to recursively pass each child in turn to the setRectStyle method. asScala is made available by the import scala.collection.JavaConverters._ statement.
Because the function is recursive, but the recursive call is not in the tail position (the last statement of the function), it is not tail-recursive. What this means is if you pass a huge scene to the function, you might get a StackOverflowException. You should be fine with any reasonable size of scene. (However, as an exercise, you might want to write a tail-recursive version so that the function is stack safe.)
This code is going to get slower and less efficient the bigger the scene becomes. Possibly not your top concern in UI code, but a bad smell all the same.
So, as we've seen, having to browse through a scene is challenging, inefficient and potentially error prone. Is there a better way? You bet!
The following will only work if you have control over the definition of the scene for your data elements. If you don't, you're stuck with solutions based upon the above.
The simplest solution is to retain a reference to the Rectangle whose style you want to change as part of a class, then access it directly as needed. For example:
import scalafx.Includes._
import scalafx.scene.control.Label
import scalafx.scene.layout.{StackPane, VBox}
import scalafx.scene.shape.Rectangle
final class Element {
// Key rectangle whose style is updated when the element is selected.
private val rect = new Rectangle {
width = 600
height = 400
}
// Scene representing an element.
val scene = new VBox {
children = List(
new VBox {
children = List(
new StackPane {
children = List(
// Ignore ImageView for now: not too important.
rect // Note: This is the rectangle defined above.
)
}
)
},
new Label {
text = "Some label"
}
)
}
// Call when element selected.
def setRectSelected(): Unit = rect.style = "-fx-fill: #a001fc;"
// Call when element deselected (which I assume you'll require).
def setRectDeselected(): Unit = rect.style = "-fx-fill: #000000;"
}
Clearly, you could pass a data reference as an argument to the class and use that to populate the scene as you like. Whenever you need to change the style, calling one of the two latter functions achieves what you need with surgical precision, no matter what the scene structure looks like.
But there's more!
One of the truly great features about ScalaFX/JavaFX is that it has observable properties that can be used to make the scene manage itself. You will find that most fields on a UI node are of some type "Property". What this allows you to do is to bind a property to the field, such that when you change the property, you change the scene accordingly. When combined with event handlers, the scene takes care of everything all by itself.
Here, I've reworked the latter class. Now, it has a handler that detects when the scene is selected and deselected and reacts by changing the property that defines the style of the Rectangle.
import scalafx.Includes._
import scalafx.beans.property.StringProperty
import scalafx.scene.control.Label
import scalafx.scene.input.MouseButton
import scalafx.scene.layout.{StackPane, VBox}
import scalafx.scene.shape.Rectangle
final class Element {
// Create a StringProperty that holds the current style for the Rectangle.
// Here we initialize it to be unselected.
private val unselected = "-fx-fill: #000000;"
private val selected = "-fx-fill: #a001fc;"
private val styleProp = new StringProperty(unselected)
// A flag indicating whether this element is selected or not.
// (I'm using a var, but this is heavily frowned upon. A better mechanism might be
// required in practice.)
private var isSelected = false
// Scene representing an element.
val scene = new VBox {
children = List(
new VBox {
children = List(
new StackPane {
children = List(
// Ignore ImageView for now: not too important.
// Key rectangle whose style is bound to the above property.
new Rectangle {
width = 600
height = 400
style <== styleProp // <== means "bind to"
}
)
}
)
},
new Label {
text = "Some label"
}
)
// Add an event handler. Whenever the VBox (or any of its children) are
// selected/unselected, we just change the style property accordingly.
//
// "mev" is a "mouse event".
onMouseClicked = {mev =>
// If this is the primary button, then change the selection status.
if(mev.button == MouseButton.Primary) {
isSelected = !isSelected // Toggle selection setting
styleProp.value = if(isSelected) selected
else unselected
}
}
}
}
Let me know how you get on...
im building a basic game in the style of the original pokemon games using the ruby gosu library. Ive managed to figure out how to move the originally loaded sprite about but i cant figure out how to clear that sprite and draw the new sprite e.g. back view in its place.
Ive been looking throught the documentation and came across the "insert" method, although im not sure if this is what i want. Any help?
im creating the var in the initialize method then drawing it later on like so:
def initialize
#character_image = Gosu::Image.new("media/images/char.png", :tileable => false)
end
def draw
#character_image.draw(#character_location_X, #character_location_Y, 1)
end
You need to make a class for your character, which needs an update and draw function. In the update function, when input such as WASD is received you can switch the image of the sprite. If you don't have a sprite sheet, you'll have to load multiple images and switch between them.
Here's some ruby pseudocode to help you:
#back_image = Gosu::Image.new("media/images/back.png")
#front_image = Gosu::Image.new("media/images/front.png")
#left_image = Gosu::Image.new("media/images/left.png")
#right_image = Gosu::Image.new("media/images/right.png")
current_image = front_image
This goes in your update function:
if up
current_image = back_image
elsif down
current_image = front_image
elsif right
current_image = right_image
elsif left
current_image = left_image
end
Then in your draw function all you need to do is
def draw
#current_image.draw(#character_location_X, #character_location_Y, 1)
end
This is a pretty basic way, but if you use a sprite sheet, you can create your own animation class that Gosu can use that allows you to select between certain ranges of frames of your character spritesheet.
I'm using Actionscript 2.0 for a mobile phone and can't get my head around Events.
I'm creating a class object with all my code and using a group of functions (all as direct 1st level children of the class). There's one function that creates a Movieclip with a square on it and sets the onPress event to another function called hit:
public function draw1Sqr(sName:String,pTL:Object,sSide:Number,rgb:Number){
// create a movie clip for the Sqr
var Sqr:MovieClip=this.canvas_mc.createEmptyMovieClip(sName,this.canvas_mc.getNextHighestDepth());
// draw square
Sqr.beginFill(rgb);
//etc ...more lines
//setup properties (these are accessible in the event)
Sqr.sSide=sSide;
Sqr.sName=sName;
//setup event
Sqr.onPress = hit; // this syntax seems to lead to 'this' within
// the handler function to be Sqr (movieclip)
//Sqr.onPress = Delegate.create(this, hit);
//I've read a lot about Delegate but it seems to make things harder for me.
}
Then in my event handler, I just cannot get the scope right...
public function hit(){
for (var x in this){
trace(x + " == " + this[x]);
}
//output results
//onPress == [type Function]
//sName == bSqr_7_4
//sSide == 20
trace(eval(this["._parent"])); //undefined
trace(eval(this["._x"])); //undefined
}
For some reason, although the scope is set to the calling object (Sqr, a Movieclip) and I can access properties I defined, I can't use the 'native' properties of a Movieclip object.
Any suggestions on how I can access the _x, _y and other properties of the Movieclip object that is pressed.
Use the array accessor or the dot accessor, but not both. For example:
trace(this._parent); // OR
trace(this["_parent"]);
As for the results of your iteration, I recall AS2 being screwy on this front. IIRC only dynamic properties are returned when looping with for ... in. This prevents Objects (which often serve as hash maps) from including their native properties when all you want are the key/value pairs you set yourself.
Also - the eval() function can be easily overused. Unless you absolutely must execute a String of AS2 that you don't have at compile-time I would recommend avoiding it. Happy coding!
I have designed a group of three uitabpanels objects.
htab = uitabgroup('v0');
th1 = uitab('v0',htab,'title','Panel 1','ButtonDownFcn',...
#th1_ButtonDownFcn);
th2 = uitab('v0',htab,'title','Panel 2','ButtonDownFcn',...
#th2_ButtonDownFcn);
th3 = uitab('v0',htab,'title','Panel 3','ButtonDownFcn',...
#th3_ButtonDownFcn);
My intention is having a smooth transition between them when I change the selected uipanel through the mouse click. I pretend to achieve it changing the 'Visible' property of the elements contained inside them using the ButtonDownFcn function ( I got this idea based on the description section of this page).
set(handles.th2,'Visible','off');
set(handles.th3,'Visible','off');
...
function th1_ButtonDownFcn(hObject, eventdata)
handles = guidata(fh);
set(handles.th1,'Visible','on');
set(handles.th2,'Visible','off');
set(handles.th3,'Visible','off');
guidata(fh,handles);
end
function th2_ButtonDownFcn(hObject, eventdata)
handles = guidata(fh);
set(handles.th1,'Visible','off');
set(handles.th2,'Visible','on');
set(handles.th3,'Visible','off');
guidata(fh,handles);
end
function th3_ButtonDownFcn(hObject, eventdata)
handles = guidata(fh);
set(handles.th1,'Visible','off');
set(handles.th2,'Visible','off');
set(handles.th3,'Visible','on');
guidata(fh,handles);
end
where
fh: handle of the figure where they are contained the uitabpanels.
handles.th1, handles.th2, handles.th3: handles of the elements contained into each uitabpanel respectively.
However, it has not worked (I click on each one of uitabpanel's tabs and the visibility of them do not change) and I do not understand why.
In conclusion, the ButtonDownFcn and SelectionChangeFcn functions of an UITAB are already active when you click in the tabĀ“s label. So it is not possible to achieve the desired target (smooth optical transition) because the obtained result (modifying the mentioned functions) is the same that doing nothing.