Author Archives: Kevin

Create something like the Widget Box as in the Qt Designer

Widget Box

Widget Box

Widget Box

There is something called the Widget Box in the Qt Designer. It contains a list of widgets separated by categories. Each category button can be clicked in order to expand and collapse the list below the button.

You might want something like the Widget Box for one reason or another, to display your own collapsible list of items.

Tree Widget

In my approach in recreating the Widget Box I used a Tree Widget because it already has the basic idea of expanding and collapsing items in the list to display and hide its child widgets. The gist of turning the Tree Widget into a Widget Box is adding buttons as top level items and adding a frame with a layout as the child of those top level items. The button should then expand and collapse its own Tree Widget Item when clicked to display and hide the contents of a category. The button will require a custom class inheriting the QPushButton class in order to expand and collapse the Tree Widget Items.

You might want to disable root decoration and set indentation to 0 on the Tree Widget to turn it into a flat list. The custom button type is named QtCategoryButton in this snippet.

MyApplication::MyApplication(QWidget *parent, Qt::WFlags flags)
	: QMainWindow(parent, flags)
{
	ui.setupUi(this);

	ui.treeWidget->setRootIsDecorated(false);
	ui.treeWidget->setIndentation(0);

	// First category
	{
		QTreeWidgetItem* pCategory = new QTreeWidgetItem();
		ui.treeWidget->addTopLevelItem(pCategory);
		ui.treeWidget->setItemWidget(pCategory, 0,
			new QtCategoryButton("Category 1", ui.treeWidget, pCategory));

		QFrame* pFrame = new QFrame(ui.treeWidget);
		QBoxLayout* pLayout = new QVBoxLayout(pFrame);
		pLayout->addWidget(new QPushButton("Btn1"));
		pLayout->addWidget(new QPushButton("Btn2"));

		QTreeWidgetItem* pContainer = new QTreeWidgetItem();
		pContainer->setDisabled(true);
		pCategory->addChild(pContainer);
		ui.treeWidget->setItemWidget(pContainer, 0, pFrame);
	}

	// Second category
	{
		QTreeWidgetItem* pCategory = new QTreeWidgetItem();
		ui.treeWidget->addTopLevelItem(pCategory);
		ui.treeWidget->setItemWidget(pCategory, 0,
			new QtCategoryButton("Category 2", ui.treeWidget, pCategory));

		QFrame* pFrame = new QFrame(ui.treeWidget);
		QBoxLayout* pLayout = new QHBoxLayout(pFrame);
		pLayout->addWidget(new QPushButton("Btn1"));
		pLayout->addWidget(new QPushButton("Btn2"));

		QTreeWidgetItem* pContainer = new QTreeWidgetItem();
		pContainer->setDisabled(true);
		pCategory->addChild(pContainer);
		ui.treeWidget->setItemWidget(pContainer, 0, pFrame);
	}
}

Custom button

The custom button is a quite simple class, all it does it catch the pressed() signal and expands or collapses the Tree Widget Item it is bound to.

class QtCategoryButton : public QPushButton
{
	Q_OBJECT
public:
	QtCategoryButton(const QString& a_Text, QTreeWidget* a_pParent,
		QTreeWidgetItem* a_pItem);

private slots:
	void ButtonPressed();

private:
	QTreeWidgetItem* m_pItem;
};

 

QtCategoryButton::QtCategoryButton( const QString& a_Text,
		QTreeWidget* a_pParent, QTreeWidgetItem* a_pItem )
	: QPushButton(a_Text, a_pParent)
	, m_pItem(a_pItem)
{
	connect(this, SIGNAL(pressed()), this, SLOT(ButtonPressed()));
}

void QtCategoryButton::ButtonPressed()
{
	m_pItem->setExpanded( !m_pItem->isExpanded() );
}

Finally

Custom Widget Box

Custom Widget Box

If everything went well you should get something like this. You can of course use any other widgets, not just buttons.

Getting started with Google Play Game Services

Introduction

As I am writing this I am simply noting down the steps I take to get Google Play Game Services to work. I am following this tutorial along with a lot of Googling https://developers.google.com/games/services/android/quickstart

Requirements

  1. Android (Google Play) Developer Account.
  2. Eclipse all set up to work with the Android SDK.
  3. A keystore for signing your apps.
  4. The Type-A-Number Challenge project https://developers.google.com/games/services/downloads/#samples.
  5. Google Play services SDK https://developer.android.com/google/play-services/setup.html.

Import the Google Play services library

Import the Google Play services library project code into your Eclipse workspace.

  1. File > Import > Android > Existing Android Code Into Workspace.
  2. Locate the Google Play services library. Mine was in C:\Program Files (x86)\Android\android-sdk\extras\google\google_play_services\libproject\google-play-services_lib.
  3. Be sure to select the Copy Projects into workspace option.

Import the sample projects

Import the TypeANumber and BaseGameUtils projects code into your Eclipse workspace.

  1. File > Import > Android > Existing Android Code Into Workspace.
  2. Locate the sample projects you downloaded earlier and import them both.
  3. I used the Copy Projects into workspace option for these projects as well. Later I found a problem when I did not do this, I think it is because some projects were located on a different drive and Eclipse (or the Android SDK) had problems with that.
  4. Tell both projects to use the google-play-services_lib project as a library by going in the project properties > Android and add it to the list of libraries.

Errors

At this point I got a whole bunch of errors in Eclipse with this error at the top.

AppStateClient cannot be resolved to a type

Most of the errors came from the BaseGameUtils project. To fix this I simply hovered over the error in the code and selected "Fix project setup..." and *poof* all my BaseGameUtils errors were gone.

There were still two errors left from the TypeANumber project but I simply used the same solution, hover over the error and select "Fix project setup..." it would then add references to the google-play-services lib and jar files.

Perhaps I did something wrong, you might not get these errors since I fixed the above steps after figuring some problems out.

Change the package name

According to the tutorial I should now change the package name of the TypeANumber project in its AndroidManifest.xml file. I changed com.google.example.games.tanc into com.fktrth.typeanumber.

A lot of errors about 'R' not being able to be resolved to a variable popped up since I also had to change the package name in the code itself. Then I looked up all the incorrect imports of com.google.example.games.tan.R and changed it to the correct one com.fktrth.typeanumber.R. This fixed all the remaining errors.

Google Play Developers Console

Now we have done a part in Eclipse now it is time to continue on the Developers Console side by following this tutorial https://developers.google.com/games/services/console/enabling#step_2_add_your_game_to_the_dev_console.

  1. Go to the Game services tab.
  2. Accept all the terms and conditions and stuff.
  3. Press the big button in the center of the screen to add a new game.
  4. Select that you are not using Google API's in your game yet.
  5. Use "Type-a-Number Challenge" as the name of your game.
  6. Select puzzle game and press continue.

Generate OAuth 2.0 key

Following this tutorial I will generate an OAuth 2.0 key https://developers.google.com/games/services/console/enabling#step_3_generate_an_oauth_20_client_id.

  1. Press the "Linked apps" tab (the second from the top).
  2. Choose to link an Android app.
  3. Enter the package name from the AndroidManifest.xml file "com.fktrth.typeanumber"
  4. Press "Save and continue".
  5. Then authorize the app by clicking the button in step 2.
  6. I ignored all settings in the window that popped up (name, logo and site URL) and pressed continue.
  7. Now you need to enter a Signing certificate fingerprint in the form of a SHA1 hash.
    1. Use a command prompt window and navigate to your keystore's location
    2. Type "keytool -exportcert -alias [KeyAlias] -keystore [KeyStoreLocation] -list -v
    3. It should print out some info along with a SHA1 hash. Enter this hash in the field in the Developers Console.
    4. You can also use a debug certificate by finding the debug.keystore file. For me it was located in C:\Users\[UserName]\.android
    5. Then type "keytool -exportcert -alias androiddebugkey -keystore [KeyStoreLocation] -list -v". When asked for a password just press enter so you enter an empty password.
  8. After entering the certificate fingerprint press "Create client".
  9. You should get an Application ID now, you need to enter this in one of the resources of your game project later.

Add some achievements and leaderboards

Now that is all done I will add a couple achievements like the tutorial suggests along with two leaderboards

Test accounts

Press the Testing tab to add testing accounts. When your app is not published yet only those accounts can log in and use the Google Play Game Services so make sure to add the account you use. For me my account was already added because I use the same account for my developer account as for playing games.

Add Application ID to the source

After generating and entering the OAuth 2.0 key you should have gotten an Application ID. You need to add this ID in res/values/ids.xml of your game project. Enter your Application ID in the app_id field of the ids.xml file. Also fill in all the achievement and leaderboard IDs. This should be easy enough.

Running the game - or so I hoped

When all of that was done it seemed like it was time to actually run the game on my tablet and see if it works. Unfortunately the app immediately crashed. Looking in my console log I found the error

Could not find google-play-services_lib.apk!

A quick look on Google found this page http://stackoverflow.com/questions/16756561/android-could-not-find-google-play-services-lib-apk-error. Apparently the automagic "Fix project setup..." of Eclipse screwed up some settings for Android and I had to remove a project from the build path of the game project. However this created some more errors. After some thinking I remembered I had this problem before when using library projects. Apparently Android could not link properly to the google-play-services_lib project and I think it is because it is not located on the same drive as my workspace (the library is on C and my projects and workspaces are all on D). To fix this problem I re-imported all projects with the option "Copy Projects into workspace" selected.

After that was fixed the game still crashed. I found this post on Stack Overflow http://stackoverflow.com/questions/16595225/initializing-games-client-in-android which said I should enter my Application ID. I forgot to do that step so I entered all the IDs I could find and the app could finally run without crashing!

Really running the game!

Finally I could run the game! Signing in worked, it was pretty exciting. All the achievements and leaderboards worked.