how to make interact between nodes that are made in different cpps...? - android

There are over 20 Layers like Layer01.cpp, Layer02.cpp, Layer03.cpp ...
and there is a tableview named "itemSlots" in HelloWorld.cpp.
When user touch dragon button in Layer01,
a banana sprite in HelloWorld.cpp will be dissappeared,
and a poop appear in itemSlots.
That is all I want to do and I thought it is quite simple.
I made Layers and tableview also, like below,
but still couldn't find a way to make interact between button and sprite
which are made in different cpps.
Layer01.h
#ifndef __LAYER01__H__
#define __LAYER01__H__
#include "cocos2d.h"
#include "ui/CocosGUI.h"
class Layer01 : public cocos2d::LayerColor
{
public:
Layer01();
virtual bool init();
cocos2d::ui::Button* dragon;
void touchDragon();
private:
};
#endif
Layer01.cpp
#include "Layer01.h"
USING_NS_CC;
Layer01::Layer01()
{
bool bOk = initWithColor(Color4B::BLACK, 750, 400);
if (bOk == true) {
this->autorelease();
init();
};
}
bool Layer01::init()
{
scene01 = Sprite::create("images/scene01.jpg");
scene01->setScale(this->getContentSize().width/sc02a->getContentSize().width);
scene01->setAnchorPoint(Point::ZERO);
scene01->setPosition(Point::ZERO);
this->addChild(scene01);
dragon = ui::Button::create("images/dragon.png", "images/dragon.png", "");
dragon->setContentSize(Size(50, 50));
dragon->setPosition(Point(250,300));
dragon->addClickEventListener(CC_CALLBACK_0(Layer01::touchDragon, this));
this->addChild(dragon);
return true;
}
void Layer01::touchDragon()
{
/*
layer01->removeChild(banana);
auto poopCell = itemSlots->cellAtIndex(2);
poopCell->addChild(poop);
*/
}
HelloWorld.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
#include "Layer01.h"
#include "ui/CocosGUI.h"
#include "cocos-ext.h"
#include "CustomTableViewCell.h"
class HelloWorld : public cocos2d::Layer,
public cocos2d::extension::TableViewDataSource,
public cocos2d::extension::TableViewDelegate
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
CREATE_FUNC(HelloWorld);
cocos2d::Sprite* banana;
cocos2d::Sprite* poop;
cocos2d::extension::TableView* itemSlots;
virtual void tableCellTouched(cocos2d::extension::TableView* table,
cocos2d::extension::TableViewCell* cell);
virtual cocos2d::Size tableCellSizeForIndex
(cocos2d::extension::TableView* table, ssize_t idx);
virtual cocos2d::extension::TableViewCell* tableCellAtIndex
(cocos2d::extension::TableView* table, ssize_t idx);
virtual ssize_t numberOfCellsInTableView(cocos2d::extension::TableView* view);
};
#endif // __HELLOWORLD_SCENE_H__
HelloWorld.cpp
#include "HelloWorldScene.h"
USING_NS_CC;
USING_NS_CC_EXT;
Scene* HelloWorld::createScene()
{
auto scene = Scene::create();
auto layer = HelloWorld::create();
scene->addChild(layer);
return scene;
}
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
layer01 = new Layer01();
layer->setPosition(Point(0, 100));
this->addChild(layer01);
banana = Sprite::create("images/banana.png");
banana->setPosition(Point(300,300));
layer01->addChild(banana);
poop = Sprite::create("images/poop.png");
itemSlots = TableView::create(this, Size(535, 70));
itemSlots->setDirection(ScrollView::Direction::HORIZONTAL);
itemSlots->setPosition(Point(115, 15));
itemSlots->setDelegate(this);
this->addChild(itemSlots);
itemSlots->reloadData();
return true;
}
void HelloWorld::tableCellTouched(TableView* table, TableViewCell* cell)
{
}
Size HelloWorld::tableCellSizeForIndex(TableView* table, ssize_t idx)
{
return Size(77, 77);
}
TableViewCell* HelloWorld::tableCellAtIndex(TableView* table, ssize_t idx)
{
auto string = String::createWithFormat("%ld", idx);
TableViewCell* cell = table->dequeueCell();
if (cell == false)
{
cell = new CustomTableViewCell();
cell->autorelease();
auto sprite01 = Sprite::create();
sprite01->setAnchorPoint(Point::ZERO);
sprite01->setPosition(Point::ZERO);
cell->addChild(sprite01);
auto label = LabelTTF::create(string->getCString(), "arial", 20.0);
label->setAnchorPoint(Point::ZERO);
label->setPosition(Point(5, 5));
label->setTag(120);
cell->addChild(label);
}
else {
auto label = (LabelTTF*)cell->getChildByTag(120);
label->setString(string->getCString());
}
return cell;
}
ssize_t HelloWorld::numberOfCellsInTableView(TableView* table)
{
return 20;
}

The easiest but unsafe way is to do following:
//Layer01.cpp
#include "HelloWorld.h"
...
void Layer01::touchDragon()
{
removeChild(banana);
// As your parent is a HelloWorld you can cast it:
HelloWorld* helloWorld = (HelloWorld*)getParent();
auto poopCell = helloWorld->itemSlots->cellAtIndex(2);
poopCell->addChild(helloWorld->poop);
}
But poop will be automatically garbage collected at that time. You need to retain it after creating and release when no longer need.
The better option would be to have a pointer to the HelloWorld layer in the Layer01 and have a separate method for setting a poop:
Layer01.h
// Forward declaration
class HelloWorld;
class Layer01
{
...
HelloWorld* m_hellowWorld;
// Don't forget about create function
static Layer01* create(HelloWorld* helloWorld)
{
Layer01* result = new (std::nothrow) Layer01();
if(result && result->init(helloWorld))
{
result->autorelease();
}
else
{
delete result;
result = nullptr;
}
return result;
}
bool Layer01::init(HelloWorld* helloWorld);
...
};
Layer01.cpp
#include "Layer01.h"
#include "HelloWorld.h"
Layer01::Layer01()
: HelloWorld(nullptr)
{}
bool Layer01::init(HelloWorld* helloWorld)
{
removeChild(banana);
m_hellowWorld = helloWorld;
...
}
void Layer01::touchDragon()
{
m_hellowWorld->setPoop();
}
HelloWorld.h
class HelloWorld
{
...
void setPoop();
...
};
HelloWorld.cpp
...
void HelloWorld::setPoop()
{
auto poopCell = itemSlots->cellAtIndex(2);
poopCell->addChild(Sprite::create("images/poop.png"));
}

Related

Implement native binder code of c++

I have the following code for native binder implementation.
#define LOG_TAG "binder_demo"
#include <stdlib.h>
#include <utils/RefBase.h>
#include <utils/Log.h>
#include <binder/TextOutput.h>
#include <binder/IInterface.h>
#include <binder/IBinder.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
using namespace android;
#define INFO(...) \
do { \
printf(__VA_ARGS__); \
printf("\n"); \
ALOGD(__VA_ARGS__); \
} while(0)
void assert_fail(const char *file, int line, const char *func, const char *expr) {
INFO("assertion failed at file %s, line %d, function %s:",
file, line, func);
INFO("%s", expr);
abort();
}
#define ASSERT(e) \
do { \
if (!(e)) \
assert_fail(__FILE__, __LINE__, __func__, #e); \
} while(0)
#define PLOG aout
class IDemo : public IInterface {
public:
enum {
ALERT = IBinder::FIRST_CALL_TRANSACTION,
PUSH,
ADD
};
// Sends a user-provided value to the service
virtual void push(int32_t data) = 0;
// Sends a fixed alert string to the service
virtual void alert() = 0;
// Requests the service to perform an addition and return the result
virtual int32_t add(int32_t v1, int32_t v2) = 0;
DECLARE_META_INTERFACE(Demo); // Expands to 5 lines below:
};
// Client
class BpDemo : public BpInterface<IDemo> {
public:
BpDemo(const sp<IBinder>& impl) : BpInterface<IDemo>(impl) {
ALOGD("BpDemo::BpDemo()");
}
virtual void push(int32_t push_data) {
Parcel data, reply;
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
data.writeInt32(push_data);
aout << "BpDemo::push parcel to be sent:\n";
data.print(PLOG); endl(PLOG);
remote()->transact(PUSH, data, &reply);
aout << "BpDemo::push parcel reply:\n";
reply.print(PLOG); endl(PLOG);
ALOGD("BpDemo::push(%i)", push_data);
}
virtual void alert() {
Parcel data, reply;
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
data.writeString16(String16("The alert string"));
remote()->transact(ALERT, data, &reply, IBinder::FLAG_ONEWAY); // asynchronous call
ALOGD("BpDemo::alert()");
}
virtual int32_t add(int32_t v1, int32_t v2) {
Parcel data, reply;
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
data.writeInt32(v1);
data.writeInt32(v2);
aout << "BpDemo::add parcel to be sent:\n";
data.print(PLOG); endl(PLOG);
remote()->transact(ADD, data, &reply);
ALOGD("BpDemo::add transact reply");
reply.print(PLOG); endl(PLOG);
int32_t res;
status_t status = reply.readInt32(&res);
ALOGD("BpDemo::add(%i, %i) = %i (status: %i)", v1, v2, res, status);
return res;
}
};
DECLARE_META_INTERFACE(Demo,"Demo"); // Expands to 5 lines below:
// Server
class BnDemo : public BnInterface<IDemo> {
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
};
status_t BnDemo::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
ALOGD("BnDemo::onTransact(%i) %i", code, flags);
data.checkInterface(this);
data.print(PLOG); endl(PLOG);
switch(code) {
case ALERT: {
alert(); // Ignoring the fixed alert string
return NO_ERROR;
} break;
case PUSH: {
int32_t inData = data.readInt32();
ALOGD("BnDemo::onTransact got %i", inData);
push(inData);
ASSERT(reply != 0);
reply->print(PLOG); endl(PLOG);
return NO_ERROR;
} break;
case ADD: {
int32_t inV1 = data.readInt32();
int32_t inV2 = data.readInt32();
int32_t sum = add(inV1, inV2);
ALOGD("BnDemo::onTransact add(%i, %i) = %i", inV1, inV2, sum);
ASSERT(reply != 0);
reply->print(PLOG); endl(PLOG);
reply->writeInt32(sum);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
class Demo : public BnDemo {
virtual void push(int32_t data) {
INFO("Demo::push(%i)", data);
}
virtual void alert() {
INFO("Demo::alert()");
}
virtual int32_t add(int32_t v1, int32_t v2) {
INFO("Demo::add(%i, %i)", v1, v2);
return v1 + v2;
}
};
// Helper function to get a hold of the "Demo" service.
sp<IDemo> getDemoServ() {
sp<IServiceManager> sm = defaultServiceManager();
ASSERT(sm != 0);
sp<IBinder> binder = sm->getService(String16("Demo"));
// TODO: If the "Demo" service is not running, getService times out and binder == 0.
ASSERT(binder != 0);
sp<IDemo> demo = interface_cast<IDemo>(binder);
ASSERT(demo != 0);
return demo;
}
int main(int argc, char **argv) {
if (argc == 1) {
ALOGD("We're the service");
defaultServiceManager()->addService(String16("Demo"), new Demo());
android::ProcessState::self()->startThreadPool();
ALOGD("Demo service is now ready");
IPCThreadState::self()->joinThreadPool();
ALOGD("Demo service thread joined");
} else if (argc == 2) {
INFO("We're the client: %s", argv[1]);
int v = atoi(argv[1]);
sp<IDemo> demo = getDemoServ()
demo->alert();
demo->push(v);
const int32_t adder = 5;
int32_t sum = demo->add(v, adder);
ALOGD("Addition result: %i + %i = %i", v, adder, sum);
}
return 0;
}
The problem is how to compile and test it on a android platform. I don't want to build a new binary. What I want is that the code should compile on a running android platform and result should be displayed on a terminal like adb shell.

Understanding and implementing native Binders in android using C++

I want to implement a simple IPC mechanism using Binders in android. For that, I searched on the Internet and found this. I compiled it and it runs fine on my Android device. I tried to take an overall understanding of the program, by searching for each class on AOSP, but everything got more difficult and messed up. Can anyone please explain (just high level), maybe by adding more comments, so that it also helps some future visitors. Here's the code is taken from there:
#define LOG_TAG "binder_demo"
#include <stdlib.h>
#include "utils/RefBase.h"
#include "utils/Log.h"
#include "utils/TextOutput.h"
#include <binder/IInterface.h>
#include <binder/IBinder.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
using namespace android;
#define INFO(...) \
do { \
printf(__VA_ARGS__); \
printf("\n"); \
LOGD(__VA_ARGS__); \
} while(0)
void assert_fail(const char *file, int line, const char *func, const char *expr) {
INFO("assertion failed at file %s, line %d, function %s:",
file, line, func);
INFO("%s", expr);
abort();
}
#define ASSERT(e) \
do { \
if (!(e)) \
assert_fail(__FILE__, __LINE__, __func__, #e); \
} while(0)
// Where to print the parcel contents: aout, alog, aerr. alog doesn't seem to work.
#define PLOG aout
// Interface (our AIDL) - Shared by server and client
class IDemo : public IInterface {
public:
enum {
ALERT = IBinder::FIRST_CALL_TRANSACTION,
PUSH,
ADD
};
// Sends a user-provided value to the service
virtual void push(int32_t data) = 0;
// Sends a fixed alert string to the service
virtual void alert() = 0;
// Requests the service to perform an addition and return the result
virtual int32_t add(int32_t v1, int32_t v2) = 0;
DECLARE_META_INTERFACE(Demo); // Expands to 5 lines below:
//static const android::String16 descriptor;
//static android::sp<IDemo> asInterface(const android::sp<android::IBinder>& obj);
//virtual const android::String16& getInterfaceDescriptor() const;
//IDemo();
//virtual ~IDemo();
};
// Client
class BpDemo : public BpInterface<IDemo> {
public:
BpDemo(const sp<IBinder>& impl) : BpInterface<IDemo>(impl) {
LOGD("BpDemo::BpDemo()");
}
virtual void push(int32_t push_data) {
Parcel data, reply;
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
data.writeInt32(push_data);
aout << "BpDemo::push parcel to be sent:\n";
data.print(PLOG); endl(PLOG);
remote()->transact(PUSH, data, &reply);
aout << "BpDemo::push parcel reply:\n";
reply.print(PLOG); endl(PLOG);
LOGD("BpDemo::push(%i)", push_data);
}
virtual void alert() {
Parcel data, reply;
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
data.writeString16(String16("The alert string"));
remote()->transact(ALERT, data, &reply, IBinder::FLAG_ONEWAY); // asynchronous call
LOGD("BpDemo::alert()");
}
virtual int32_t add(int32_t v1, int32_t v2) {
Parcel data, reply;
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
data.writeInt32(v1);
data.writeInt32(v2);
aout << "BpDemo::add parcel to be sent:\n";
data.print(PLOG); endl(PLOG);
remote()->transact(ADD, data, &reply);
LOGD("BpDemo::add transact reply");
reply.print(PLOG); endl(PLOG);
int32_t res;
status_t status = reply.readInt32(&res);
LOGD("BpDemo::add(%i, %i) = %i (status: %i)", v1, v2, res, status);
return res;
}
};
//IMPLEMENT_META_INTERFACE(Demo, "Demo");
// Macro above expands to code below. Doing it by hand so we can log ctor and destructor calls.
const android::String16 IDemo::descriptor("Demo");
const android::String16& IDemo::getInterfaceDescriptor() const {
return IDemo::descriptor;
}
android::sp<IDemo> IDemo::asInterface(const android::sp<android::IBinder>& obj) {
android::sp<IDemo> intr;
if (obj != NULL) {
intr = static_cast<IDemo*>(obj->queryLocalInterface(IDemo::descriptor).get());
if (intr == NULL) {
intr = new BpDemo(obj);
}
}
return intr;
}
IDemo::IDemo() { LOGD("IDemo::IDemo()"); }
IDemo::~IDemo() { LOGD("IDemo::~IDemo()"); }
// End of macro expansion
// Server
class BnDemo : public BnInterface<IDemo> {
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
};
status_t BnDemo::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
LOGD("BnDemo::onTransact(%i) %i", code, flags);
data.checkInterface(this);
data.print(PLOG); endl(PLOG);
switch(code) {
case ALERT: {
alert(); // Ignoring the fixed alert string
return NO_ERROR;
} break;
case PUSH: {
int32_t inData = data.readInt32();
LOGD("BnDemo::onTransact got %i", inData);
push(inData);
ASSERT(reply != 0);
reply->print(PLOG); endl(PLOG);
return NO_ERROR;
} break;
case ADD: {
int32_t inV1 = data.readInt32();
int32_t inV2 = data.readInt32();
int32_t sum = add(inV1, inV2);
LOGD("BnDemo::onTransact add(%i, %i) = %i", inV1, inV2, sum);
ASSERT(reply != 0);
reply->print(PLOG); endl(PLOG);
reply->writeInt32(sum);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
class Demo : public BnDemo {
virtual void push(int32_t data) {
INFO("Demo::push(%i)", data);
}
virtual void alert() {
INFO("Demo::alert()");
}
virtual int32_t add(int32_t v1, int32_t v2) {
INFO("Demo::add(%i, %i)", v1, v2);
return v1 + v2;
}
};
// Helper function to get a hold of the "Demo" service.
sp<IDemo> getDemoServ() {
sp<IServiceManager> sm = defaultServiceManager();
ASSERT(sm != 0);
sp<IBinder> binder = sm->getService(String16("Demo"));
// TODO: If the "Demo" service is not running, getService times out and binder == 0.
ASSERT(binder != 0);
sp<IDemo> demo = interface_cast<IDemo>(binder);
ASSERT(demo != 0);
return demo;
}
int main(int argc, char **argv) {
if (argc == 1) {
LOGD("We're the service");
defaultServiceManager()->addService(String16("Demo"), new Demo());
android::ProcessState::self()->startThreadPool();
LOGD("Demo service is now ready");
IPCThreadState::self()->joinThreadPool();
LOGD("Demo service thread joined");
} else if (argc == 2) {
INFO("We're the client: %s", argv[1]);
int v = atoi(argv[1]);
sp<IDemo> demo = getDemoServ();
demo->alert();
demo->push(v);
const int32_t adder = 5;
int32_t sum = demo->add(v, adder);
LOGD("Addition result: %i + %i = %i", v, adder, sum);
}
return 0;
}
I know this is a bit late but checkout this amazing explanation by Gabriel Burca on Android IPC mechanism here. You can find a working example with a very simple C++ code from the same author here. Further it has clear instructions how to compile and add it to your AOSP source. Cheers!

Cocos2d-x Change MenuItemImage on cursor focus

Using Cocos2d-x 3.4 on Windows7.
How to change "MenuItemImage" image on mouse cursor focus? (on Windows)
** I want "mouse over(hover) effect" to MenuItemImage. **
I know, how to create "not touch" or "clicking" button.
auto button = MenuItemImage::create(
"button_normal.png",
"button_pressed.png",
[](Ref* ref){
// do anything if clicking
});
auto menuButton = Menu::create(button, NULL);
auto winSize = Director::getInstance()->getWinSize();
menuButton->setPosition(Vec2(winSize.width / 2.0, winSize.height / 2.0));
this->addChild(menuButton);
But this method is not change image on focus.
Create a EventListenerMouse to look for mouse over event.
//
// MouseOverMenuItem.h
// MouseOver
//
// Created by Baris Atamer on 3/15/15.
//
//
#ifndef __MouseOver__MouseOverMenuItem__
#define __MouseOver__MouseOverMenuItem__
#include "cocos2d.h"
USING_NS_CC;
class MouseOverMenuItem : public MenuItemImage
{
public:
~MouseOverMenuItem();
static MouseOverMenuItem * create(const std::string &normalImage, const std::string &selectedImage, const std::string &disabledImage, const ccMenuCallback& callback);
protected:
EventListenerMouse* mouseListener;
private:
void onMouseMove(Event *event);
void setMouseListener();
};
#endif /* defined(__MouseOver__MouseOverMenuItem__) */
//
// MouseOverMenuItem.cpp
// MouseOver
//
// Created by Baris Atamer on 3/15/15.
//
//
#include "MouseOverMenuItem.h"
MouseOverMenuItem::~MouseOverMenuItem()
{
_eventDispatcher->removeEventListener(mouseListener);
}
MouseOverMenuItem* MouseOverMenuItem::create(const std::string &normalImage, const std::string &selectedImage, const std::string &disabledImage, const ccMenuCallback &callback)
{
MouseOverMenuItem *ret = new (std::nothrow) MouseOverMenuItem();
if (ret && ret->initWithNormalImage(normalImage, selectedImage, disabledImage, callback))
{
ret->setMouseListener();
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
void MouseOverMenuItem::onMouseMove(Event *event)
{
EventMouse* e = (EventMouse*)event;
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 locationInNode = convertToNodeSpace(Vec2(e->getCursorX(), e->getCursorY() + visibleSize.height ));
Rect r = Rect(0,0, getContentSize().width, getContentSize().height);
// Show selected image if mouse over
r.containsPoint(locationInNode) ? selected() : unselected();
}
void MouseOverMenuItem::setMouseListener()
{
// Create a mouse listener
mouseListener = EventListenerMouse::create();
mouseListener->onMouseMove = CC_CALLBACK_1(MouseOverMenuItem::onMouseMove, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(mouseListener, this);
}
Usage :
auto button = MouseOverMenuItem::create("button_normal.png", "button_pressed.png", "", [](Ref* ref){
// do anything if clicking
log("click!");
});
button->setPosition(Vec2(winSize.width*.5, winSize.height*.5) );
// create menu, it's an autorelease object
auto menu = Menu::create(button, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);
try MenuItemImage add to Menu.
auto button = MenuItemImage::create ...
auto menu = Menu::create(button , nullptr);
addChild(menu);

Cocos2dx replacescene error

Scenario I have main scene and I click this button I want to open another scene. But I am getting following error :
undefined reference to 'OyunMenu::scene()
MainMenu.h
#ifndef MAINMENU_H_
#define MAINMENU_H_
#include "cocos2d.h"
class MainMenu : public cocos2d::CCLayer
{
public:
virtual bool init();
static cocos2d::CCScene* scene();
virtual void registerWithTouchDispatcher(void);
virtual void ccTouchesBegan(cocos2d::CCSet* touches, cocos2d::CCEvent* event);
virtual void ccTouchesMoved(cocos2d::CCSet* touches, cocos2d::CCEvent* event);
virtual void ccTouchesEnded(cocos2d::CCSet* touches, cocos2d::CCEvent* event);
virtual void ccTouchesCancelled(cocos2d::CCSet* touches, cocos2d::CCEvent* event);
void menuCloseCallback(CCObject* pSender);
CREATE_FUNC(MainMenu);
};
#endif
MainMenu.cpp
#include "MainMenu.h"
#include "SimpleAudioEngine.h"
#include "Constants.h"
#include "OyunMenu.h"
#define COCOS2D_DEBUG 1
using namespace std;
USING_NS_CC;
CCScene* MainMenu::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
MainMenu *layer = MainMenu::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
bool MainMenu::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
this->setTouchEnabled(true);
CCSprite* oyuncuBul = CCSprite::create("oyuna-basla.png");
oyuncuBul->setPosition(ccp(150,260));
oyuncuBul->setTag(menuOyuncuBul);
this->addChild(oyuncuBul, 0);
}
void MainMenu::ccTouchesBegan(cocos2d::CCSet* touches, cocos2d::CCEvent* event)
{
CCTouch *touch = (CCTouch*) (touches->anyObject());
CCPoint point = touch->getLocationInView();
point = CCDirector::sharedDirector()->convertToGL(point);
CCSprite *oyuncuBul=(CCSprite *)this->getChildByTag(menuOyuncuBul);
CCRect rectOyuncuBul = oyuncuBul->boundingBox();
if(rectOyuncuBul.containsPoint(point)){
CCDirector::sharedDirector()->replaceScene(OyunMenu::scene());
}
OyunMenu.h
#ifndef OYUNMENU_H_
#define OYUNMENU_H_
#include "cocos2d.h"
class OyunMenu : public cocos2d::CCLayer
{
public:
virtual bool init();
static cocos2d::CCScene* scene();
virtual void registerWithTouchDispatcher(void);
virtual void ccTouchesBegan(cocos2d::CCSet* touches, cocos2d::CCEvent* event);
virtual void ccTouchesMoved(cocos2d::CCSet* touches, cocos2d::CCEvent* event);
virtual void ccTouchesEnded(cocos2d::CCSet* touches, cocos2d::CCEvent* event);
virtual void ccTouchesCancelled(cocos2d::CCSet* touches, cocos2d::CCEvent* event);
void menuCloseCallback(CCObject* pSender);
CREATE_FUNC(OyunMenu);
};
#endif
OyunMenu.cpp
#include "OyunMenu.h"
#include "SimpleAudioEngine.h"
#include "Constants.h"
#define COCOS2D_DEBUG 1
using namespace std;
USING_NS_CC;
CCScene* OyunMenu::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
OyunMenu *layer = OyunMenu::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool OyunMenu::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
}
.h file
CCSprite* oyuncuBul;
.cpp file
oyuncuBul = CCSprite::create("oyuna-basla.png");
oyuncuBul->setPosition(ccp(150,260));
oyuncuBul->setTag(menuOyuncuBul);
this->addChild(oyuncuBul, 0);
void MainMenu::ccTouchesBegan(cocos2d::CCSet* touches, cocos2d::CCEvent* event)
{
CCTouch *touch = (CCTouch*) (touches->anyObject());
CCPoint point = touch->getLocationInView();
point = CCDirector::sharedDirector()->convertToGL(point);
CCRect rectOyuncuBul = oyuncuBul->boundingBox();
if(rectOyuncuBul.containsPoint(point)){
CCDirector::sharedDirector()->replaceScene(OyunMenu::scene());
}
You have to add this line in android.mk file of jni folder
../../Classes/OyunMenu.cpp
Just like i am added in my android.mk file
LOCAL_SRC_FILES := hellocpp/main.cpp\
../../Classes/Menu/AppDelegate.cpp\
../../Classes/Menu/HelloWorldScene.cpp\
../../Classes/Menu/MyScene.cpp\
../../Classes/Menu/LoadingLayer.cpp\
../../Classes/UI/NewLayer.cpp\
../../Classes/UI/HelpLayer.cpp

Qt/Necessitas - reasonable QFileDialog replacement/skin?

I'm looking for a nice way to address porting Qt applications to Qt/Necessitas (Android).
Some of the QtGUI widgets are absolutely atrocious - unfortunately, including QFileDialog.
Do you know of any replacements with a proper look and feel?
Is making QFileDialog usable anywhere near high priority for Necessitas developers?
#include <QApplication>
#include <QFileDialog>
int main(int argc, char* argv[]) {
QApplication a(argc, argv);
QString fileName = QFileDialog::getOpenFileName(NULL,
QObject::tr("Open Image"), "/home/jana", QObject::tr("Image Files (*.png *.jpg *.bmp)"));
a.exec();
}
Android does not have own, native file dialog. We can use QtAndroidExtras to invoke external application which is able to pick a file:
I wrote wrapper, that could be used for that. Here's full code:
androidfiledialog.h
#ifndef ANDROIDFILEDIALOG_H
#define ANDROIDFILEDIALOG_H
#include <QObject>
#include <QAndroidJniObject>
#include <QtAndroid>
#include <QAndroidActivityResultReceiver>
class AndroidFileDialog : public QObject
{
Q_OBJECT
public:
explicit AndroidFileDialog(QObject *parent = 0);
virtual ~AndroidFileDialog();
bool provideExistingFileName();
private:
class ResultReceiver : public QAndroidActivityResultReceiver {
AndroidFileDialog *_dialog;
public:
ResultReceiver(AndroidFileDialog *dialog);
virtual ~ResultReceiver();
void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data);
QString uriToPath(QAndroidJniObject uri);
};
static const int EXISTING_FILE_NAME_REQUEST = 1;
ResultReceiver *receiver;
void emitExistingFileNameReady(QString result);
signals:
void existingFileNameReady(QString result);
};
#endif // ANDROIDFILEDIALOG_H
androidfiledialog.cpp
#include "androidfiledialog.h"
AndroidFileDialog::ResultReceiver::ResultReceiver(AndroidFileDialog *dialog) : _dialog(dialog) {}
AndroidFileDialog::ResultReceiver::~ResultReceiver() {}
void AndroidFileDialog::ResultReceiver::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data)
{
jint RESULT_OK = QAndroidJniObject::getStaticField<jint>("android/app/Activity", "RESULT_OK");
if (receiverRequestCode == EXISTING_FILE_NAME_REQUEST && resultCode == RESULT_OK) {
QAndroidJniObject uri = data.callObjectMethod("getData", "()Landroid/net/Uri;");
QString path = uriToPath(uri);
_dialog->emitExistingFileNameReady(path);
} else {
_dialog->emitExistingFileNameReady(QString());
}
}
QString AndroidFileDialog::ResultReceiver::uriToPath(QAndroidJniObject uri)
{
if (uri.toString().startsWith("file:", Qt::CaseInsensitive)) {
return uri.callObjectMethod("getPath", "()Ljava/lang/String;").toString();
} else {
QAndroidJniObject contentResolver = QtAndroid::androidActivity().callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;");
QAndroidJniObject cursor = contentResolver.callObjectMethod("query", "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;", uri.object<jobject>(), 0, 0, 0, 0);
QAndroidJniObject DATA = QAndroidJniObject::fromString("_data");
jint columnIndex = cursor.callMethod<jint>("getColumnIndexOrThrow", "(Ljava/lang/String;)I", DATA.object<jstring>());
cursor.callMethod<jboolean>("moveToFirst", "()Z");
QAndroidJniObject result = cursor.callObjectMethod("getString", "(I)Ljava/lang/String;", columnIndex);
return result.isValid() ? result.toString() : QString();
}
}
AndroidFileDialog::AndroidFileDialog(QObject *parent) : QObject(parent)
{
receiver = new ResultReceiver(this);
}
AndroidFileDialog::~AndroidFileDialog()
{
delete receiver;
}
bool AndroidFileDialog::provideExistingFileName()
{
QAndroidJniObject ACTION_GET_CONTENT = QAndroidJniObject::fromString("android.intent.action.GET_CONTENT");
QAndroidJniObject intent("android/content/Intent");
if (ACTION_GET_CONTENT.isValid() && intent.isValid()) {
intent.callObjectMethod("setAction", "(Ljava/lang/String;)Landroid/content/Intent;", ACTION_GET_CONTENT.object<jstring>());
intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QAndroidJniObject::fromString("file/*").object<jstring>());
QtAndroid::startActivity(intent.object<jobject>(), EXISTING_FILE_NAME_REQUEST, receiver);
return true;
} else {
return false;
}
}
void AndroidFileDialog::emitExistingFileNameReady(QString result)
{
emit existingFileNameReady(result);
}
You have to add to your *.pro file:
QT += androidextras
using example:
AndroidFileDialog *fileDialog = new AndroidFileDialog();
connect(fileDialog, SIGNAL(existingFileNameReady(QString)), this, SLOT(openFileNameReady(QString)));
bool success = fileDialog->provideExistingFileName();
if (!success) {
qDebug() << "Problem with JNI or sth like that...";
disconnect(fileDialog, SIGNAL(existingFileNameReady(QString)), this, SLOT(openFileNameReady(QString)));
//or just delete fileDialog instead of disconnect
}
slot implementation:
void MyClass::openFileNameReady(QString fileName)
{
if (!fileName.isNull()) {
qDebug() << "FileName: " << fileName;
} else {
qDebug() << "User did not choose file";
}
}
Please confirm this solution works properly on your device.
You could easily build your own file dialog either with QtWidgets or QML, by using the out-of-the-box QFileSystemModel class or the FolderListModel element.
As for whether it is priority or not, at this point it seems that Necessitas will be absorbed by Digia's efforts to support Android. I doubt there will be significant efforts to style QtWidgets appropriately, since the module is marked as DONE and all the focus for UI is on QML. So, I wouldn't hold by breath if I were you. Plus the stock Qt widgets look completely ugly on non-desktop platforms.

Categories

Resources