How to get the width of an image in playn with HTML5 before rendering? - playn

In the pure Java version, calling width() or height() on Image or on ImageLayer works. But with HTML5 backend I get zero if I call it too early.
Image image = assets().getImage("images/myimage.png");
ImageLayer layer = graphics().createImageLayer(image);
float w1 = image.width();
float w2 = layer.width();
I tried right after the getImage() in the initialization code of the game and also from the paint() method, the first time paint() is called. But I always get zero with the HTML5 backend (Chrome, MacOs).
However, if I call width() after the second call to the paint() method I get the correct width.
So it seems that with the HTML5 backend the semantics is different: the width() method returns the correct width of an image / layer after it has been rendered a first time.
Is my interpretation correct and how to get the size before rendering?

The Asset Watcher is working well. Alternatively, you can add a callback to your image. When the image is loaded a 'done' function is called.
Taken from pea.java:
// Add a callback for when the image loads.
// This is necessary because we can't use the width/height (to center the
// image) until after the image has been loaded
image.addCallback(new ResourceCallback<Image>() {
#Override
public void done(Image image) {
layer.setOrigin(image.width() / 2f, image.height() / 2f);
layer.setTranslation(x, y);
peaLayer.add(layer);
}
#Override
public void error(Throwable err) {
log().error("Error loading image!", err);
}
});

Have you tried using the AssetWatcher? It looks like those first width calls are outracing the document's ability to load the image.
Here's a simple example of the AssetWatcher in action:
http://playn-2011.appspot.com/slides/index.html#37
And here's an implementation of AssetWatcher from the PlayN Showcase sample:
http://code.google.com/p/playn-samples/source/browse/showcase/core/src/main/java/playn/showcase/core/sprites/SpriteLoader.java?#99

Related

Best way to load a video before into a web page with a progress bar

I want to play a video of about 30 seconds on my website that uses html5 css and javascript. What I would like is to make sure the video is loaded before playing so it plays with out interruptions.
Any quick and simple solutions.
You'll need to implement javascript to achieve what you're looking for.
You can bind the "buffered" event, but (in Chrome at least) this works fine except that it doesn't call the last "buffered" event (i.e. it will detect 90%...94%...98%... but won't call on 100%).
Note: recent versions of jQuery should use .prop() instead of .attr()
To get around this I've used setInterval() to check the buffer every 500ms (where $html5Video is your <video> element:
var videoDuration = $html5Video.attr('duration');
var updateProgressBar = function(){
if ($html5Video.attr('readyState')) {
var buffered = $html5Video.attr("buffered").end(0);
var percent = 100 * buffered / videoDuration;
//Your code here
//If finished buffering buffering quit calling it
if (buffered >= videoDuration) {
clearInterval(this.watchBuffer);
}
}
};
var watchBuffer = setInterval(updateProgressBar, 500);

When is view frame size set in iOS10 SDK?

For several years in Swift and ObjC I've used this technique to make a circular view:
view.layer.cornerRadius = view.frame.size.width / 2
view.clipsToBounds = true
When UILayoutConstraints in the Storyboard are fixed width / height there has been no problem putting this code in viewDidLoad, or in viewWillAppear. Built in iOS9.3SDK it runs fine in iOS10 etc.
iOS10SDK shows framesize completely different to the fixed size in the Storyboard, even up to viewWillAppear, and in viewDidLayoutSubviews etc. My options are:
1) do this in viewDidAppear (awful solution)
2) hardcode the cornerRadius (works fine, but awful)
This looks like a bug (as a fixed width/height set in Storyboard should never be changed without at least a warning in the console). Is it, or is there a different place for this code now? (screenshot of test code attached)
In iOS 10, I met this issue right after I started to use Xcode 8 in june, when it was beta. This solution is needed:
Put layoutIfNeeded() right before your layer modifications:
self.view.layoutIfNeeded()
view.layer.cornerRadius = view.frame.size.width / 2
view.clipsToBounds = true
OR
place the code for corner radius to viewDidLayoutSubviews() method:
override func viewDidLayoutSubviews() {
view.layer.cornerRadius = view.frame.size.width / 2
view.clipsToBounds = true
}
This was bugging me all day today. I had the same issue in a few points I needed the correct frame size to draw custom UI elements, or apply style to views, particularly changing the corner radius. The solution I found was creating a subclass of UIViewController with the following implementation:
class BaseViewController: UIViewController {
/**
This is a helper property and a helper method that will be called
when the frame is calculated, but will prevent the formatting code
being called more than once
*/
private var didCalculateInitialFrame = false
private func checkIfFrameWasCalculated() {
if self.didCalculateInitialFrame == false {
self.viewDidCalculateInitialFrame()
self.didCalculateInitialFrame = true
}
}
//-- This is where you will tie your helper method with the view lifecycle
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.checkIfFrameWasCalculated()
}
/**
This is an overridable function that you will implement
in your subclasses, in case you need to use this approach
in multiple places of your app.
*/
func viewDidCalculateInitialFrame() {
}
}
This fixed all my issues with the storyboard. I hope this is helpful.
This is seems problem in ios10
it can be solved by overriding the controller method viewDidLayoutSubviews() or
call method layoutIfNeeded() for the view which dimension value you might need before getting its dimension.
Objective-C :[viewObject layoutIfNeeded]
Swift: viewObject.layoutIfNeeded()
if the dimension value is still not correct then use layoutIfNeeded method for the parent view of the view object.

How to detect QTableWidget scroll source (code itself/user (wheel)/user (scrollbar))?

I'm writing a program using Qt 4.8 that displays a table (QTableWidget) filled with filenames and file's params. First an user adds files to the list and then clicks process. The code itself updates the contents of the table with simple progress description. I want the table by default to be scrolled automatically to show the last processed file and that code is ready.
If I want to scroll it by hand the widget is being scrolled automatically as soon as something changes moving the viewport to the last element. I want to be able to override the automated scroll if I detect that it was the user who wanted to change view.
This behavior can be seen in many terminal emulator programs. When there's a new line added the view is scrolled but when user forces the terminal to see some previous lines the terminal does not try to scroll down.
How could I do that?
Solution:
I created an object which filters event processed by my QTableWidget and QScrollBar embedded inside. If I spot the event that should turn off automatic scrolling I just set a flag and stop scrolling view if that flag is set.
Everything is implemented inside tableController class. Here are parts of three crucial methods.
bool tableController::eventFilter(QObject* object, QEvent* event)
{
switch (event->type())
{
case QEvent::KeyPress:
case QEvent::KeyRelease:
case QEvent::Wheel:
case QEvent::MouseButtonDblClick:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
_autoScrollEnabled = false;
default:
break;
}
return QObject::eventFilter(object, event);
}
void tableController::changeFile(int idx)
{
[...]
if (_autoScrollEnabled)
{
QTableWidgetItem* s = _table.item(_engine.getLastProcessed(), 1);
_table.scrollToItem(s);
}
[...]
}
void tableController::tableController()
{
[...]
_autoScrollEnabled = true;
_table.installEventFilter(this);
_table.verticalTableScrollbar()->installEventFilter(this);
[...]
}
Thanks for all the help. I hope somebody will find it useful :)
Subclass QTableWidget and overload its wheelEvent. You can use the parameters of the supplied QWheelEvent object in order to determine if the user scrolled up or down.
Then use a simple boolean flag which is set (or reset) in your wheelEvent override. The method which is responsible for calling scrollToBottom() should then consider this boolean flag.
You will have to find a way to figure out when to set or reset that flag, e.g. always set it when the user scrolls up and reset it when the user scrolls down and the currently displayed area is at the bottom.
connect(_table->view()->verticalScrollBar(), &QAbstractSlider::actionTriggered, this, [this](int) {
_autoScrollEnabled = false;
});

How to detect Screen width/height change in Flex

I have objects placed on the screen using x/y coordinates. I want a way to update that based on changes in Screen Width/Height. So if used re-sized browser window x/y should change. How do I cick off a function every time the screen is re-sized.
You can do that by attaching an ResizeEvent listener to whatever object you want to track:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/events/ResizeEvent.html
public class Main extends Sprite {
public function Main ( ) {
stage.addEventListener(Event.RESIZE, resizeListener);
}
private function resizeListener (e:Event):void {
trace("The application window changed size!");
trace("New width: " + stage.stageWidth);
trace("New height: " + stage.stageHeight);
}
}
You can setup a listener to the Resize event on the Application tag right in the mxml.
Although you may want to explore percentage based setting instead, it would be less of a effort in most cases.
The Best Way to detect changes in screen resolution is by simply Adding a event listener on application level and use the event properties to detect changes
private function init():void
{
this.addEventListener(ResizeEvent.RESIZE, resizeApplication);
}
public function resizeApplication(event:ResizeEvent):void
{
if(this.stage.stageHeight != event.oldHeight)
{
//perform action here or just use the above properties in any way you want
}
}
I made this function public so that it can be used anywhere in the application in case the event got fired but the view attached to it was not listening.

How does one smooth an image used as a control skin?

I'm embedding an image like this:
[Embed(source="/tool_deleteUp.png")]
private static const c_deleteButton_styleUp:Class;
I'm using it like this:
_removeButton = new Button();
_removeButton.setStyle('upSkin', c_deleteButton_styleUp);
When I rotate the button, the image doesn't scale smoothly. I know the tricks one uses to scale an image loaded in an Image control, but I'm banging my head against a wall trying to figure out how to do it here.
Help!
a hacky way would be to traverse the children/grandchildren of the button, to find the corresponding Bitmap that is of type c_deleteButton_styleUp, and set its smoothing to true ... it is a big flaw of flex, that sometimes it requires classes for styling although some IDisplayObjectFactory would completely suffice for that purpose and would make your life a lot easier ... but life is life ...
don't know of a clean flex only way ... the only possibility i could think of, is to create an SWF, that contains your asset as a symbol, with smoothing turned on, and embed this symbol from that SWF ...
hope that helps ...
greetz
back2dos
A better, more general solution. Not only does it handle the above case, but it does it
Without subclasses
It works with any UIComponent, including IRawChildContainers (like Container), which hide skin children in rawChildren
It only smooths newly added items, instead of running every time the control updates.
public static function smoothChildBitmaps(object:UIComponent):void{
// Define a nested smooth method
function smoothChildren(val:UIComponent):void{
var childList:IChildList;
if(val is IRawChildrenContainer){
childList = (val as IRawChildrenContainer).rawChildren;
}
else{
childList = object;
}
for(var i:int = 0; i < childList.numChildren; i++){
var child:Bitmap = childList.getChildAt(i) as Bitmap;
if(child != null){
child.smoothing = true;
}
}
};
// Call the nested method on the object right away
smoothChildren(object);
// Set up an event handler to re-call the method when a child is added
object.addEventListener(
Event.ADDED,
function(args:Event):void{
smoothChildren(object);
}
);
}
Silly, but it works.
import flash.display.Bitmap;
import mx.controls.Button;
public class SmoothButton extends Button{
protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
for(var i:int = 0; i < this.numChildren; i++){
var child:Bitmap = this.getChildAt(i) as Bitmap;
if(child != null){
child.smoothing = true;
}
}
}
}
I do not know what you folks banged your head on no offense, just joking. I had a desk :-P
Anyway, those scripts presented are totally useless! For one thing you cannot cast a uicomponent to bitmap! The other thing is, that the seconds script with rawchildren ist more ore less the same. rawchildren gets your the children and the chrome of the container - that's it. If you have a button in a container you can try to smooth the chrome of the container - the rest stays the same since all casts to bitmap will fail.
So, did anyon rdfm?
On the other hand. One could try out stage.quality to stagequality.best. If you check the adobe forums http://forums.adobe.com/thread/427899 you will see that flex runs well - just air kind of ignores this :-(
If those two scripts ever worked - esp. the part with button as bitmap - I'll go and smash my head somewhere :-). I see NO WAY in the class hierarchy that this could work. After all, numChildren only gives you uicomponents or displayobjects but nothing more!

Resources