Jump to content

  • Log In with Google      Sign In   
  • Create Account

Codex of the Modemancer

Should've been easy: Autocomplete text in a dialog box

  Posted by , 30 May 2012 - - - - - - · 843 views
A few weeks ago I threw up a quick example about dynamically building Expandable Lists, using a simple app called TopicNotes. While it is simple, I like to tinker with it here and there to test features I'm unfamiliar with. About a week ago I was playing with TopicNotes and decided pretty quickly that it needed an autocomplete feature for entering Topics to help avoid unintentional multiple versions of the same topic (I found I had a 'Study hall' topic and a 'Study Hall' topic). I could have done a variety of string checks to avoid this, but decided that adding an AutoCompleteTextView would be the most straightforward way to go. There are a number of good tutorials and examples of using AutoCompleteTextView readily available online. It is very easy to implement in any typical Activity.

However, when you use it in a dialog box, you have to explicitly tie it to the desired dialog in a way that isn't immediately evident (at least to me) in the available tutorials. My dialog box crashed time after time, and I had narrowed my problem down to the ArrayAdapter initially. As it turned out, it was a domino effect: the ArrayAdapter was crashing because the app was apparently confused about who owned the findViewById that was taking the dialog layout that was getting the AutoCompleteTextView.

Anyway, here's the code that works, in case anyone else finds themselves in this situation.

[source lang= "java"] @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // topicnotes database topic_notes_data = new TopicNotesData(this); // The button to add new notes final Button btnAddTopicNote = (Button) findViewById(R.id.Button_AddTopicNote); btnAddTopicNote.setOnClickListener(new View.OnClickListener() { // Here's where the custom dialog is created @Override public void onClick(View v) { // custom dialog final Dialog dialog = new Dialog(context); dialog.setContentView(R.layout.addtopicnotedlg); dialog.setTitle("Add Topic Note"); // this is where we need to have dialog explicitly call findViewById final AutoCompleteTextView topicText = (AutoCompleteTextView) dialog.findViewById(R.id.AutoCompleteTopic); ArrayAdapter adapter = new ArrayAdapter(context,R.layout.list_item,getAllTopics()); topicText.setAdapter(adapter); Button saveButton = (Button)dialog.findViewById(R.id.Button_SaveTopicNote); saveButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(topicText.getText() != null){ String strTopic = topicText.getText().toString(); EditText noteText = (EditText)dialog.findViewById(R.id.EditText_Note); String strNote = noteText.getText().toString(); } dialog.dismiss(); } }); Button cancelButton = (Button)dialog.findViewById(R.id.Button_CancelTopicNote); cancelButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dialog.dismiss(); } }); dialog.show(); } });}[/source]

Digital Bones--Digging in my Game Graveyard

  Posted by , 08 May 2012 - - - - - - · 600 views
So I've been plugging away on the same laptop (Toshiba Satellite with Windows Vista) since about 2007. Yes, it's 5 years old, and has far outstripped the longevity of any other windows machine I've owned. That point aside, like a digital archaeologist, I came across some long forgotten directories, and found a game I had started programming back in 2008--a simple arcade style spaceship shooter. I stopped working on it because real life happened, and my attention simply had to be elsewhere.

In the main directory was a short video clip I had put together using Anim8or and Bryce that I was going to use for the game intro. Here are some screenshots.

Posted ImageINVASION!
Posted ImageThe Saucers Approach Earth!
Here are some shots of the prototype game screen. Just an image of Earth, with wave after wave of saucers flying past. After each pass, the saucers would get smaller as they get nearer to the planet. I here were rockets that you fire after the invaders, but the animation and explosions were fairly crude.

Posted Image

After I stumbled across this program, I suddenly remembered how much I enjoyed working it. Maybe I'll have to try and reanimate the project as an Android game.



Focus, Focus--Design Documents Can Help

  Posted by , 05 May 2012 - - - - - - · 662 views

I've been programming as a hobby off and on for over 10 years. To this day, I consider myself an "advanced beginner." My gateway into programming began with C++ and a copy of Ian Parberry's Learn Computer Game Programming with DirectX 7.0 (a very, very good book in my opinion). When I started to think that I'd really like to pursue game programming, I also got my hands on Game Design: Secrets of the Sages, edited by Marc Salzman. It was an interesting book, but the part that I remember even today is mainly the game pre-production part of the book, which emphasized the importance of design documents, story boarding, and the like. Unfortunately, I promptly ignored the advice as not applicable to small projects like mine.

I wish I hadn't ignored it. When it comes to games, I used to have a rather annoying self-defeating approach to development, in that my simple idea would quickly be overcome by feature creep. Lack of focus and direction is, I'm willing to bet, the biggest obstacle to single-person and small team game development. Lack of focus on a design can drag development out insufferably. A personal example of this is my first attempt at a true video game--it was a board game inspired by the game of Checkers called KingMe! What started out as a simple one-or-two player game idea soon morphed into a monstrosity, complete with 8 different game variations and chat-enabled multiplayer support. It looked great in my head, and in my head it remained. I soon realized that development was grinding to a halt, so I broke the concept into three game versions: a "Granite" (simple version, freeware), and "Iron" version (same as Granite, but with networked multiplayer support, and a "Gold" version (everything else). Fortunately, I was able to finish my "KingMe! Iron" version in 2003, but it took 2 to 3 times as long as it should have. The Iron and Gold versions were never completed.

Posted ImageScreenshot of the KingMe! Granite game--my first game that
barely made it out of a bog of feature creep.
Fast forward several years to the present day and my current project, Titan Trivia. When I decided to go ahead with Titan, my old habit paid a visit with all kinds of cool ideas, but I was on to it. I decided I needed something to focus on, a document that would keep me tuned to my original game design. That's not to say that changes haven't been made, but even now I'm surprised how well this document has kept me focused. In fact, I found that contrary to my original attitude toward design documents (that they would inhibit creativity), my Titan Triva document in fact gave me a consistent starting point for more relevant inspiration. It's not a complicated or sophisticated document--it's simply a few slides I threw together in OpenOffice that outlines the basics of design and function ideas, but I referred to it often in the initial days of putting together the pieces of the game.

I'll wrap this up here, but below are a few comparisons of my original design document concepts beside the more-or-less final versions of the interface.

Posted Image

Posted ImageThe "Load Databases" button is a convenience button for me as I add trivia questions.
It won't be on the actual release version.

Posted Image



Coding Android Dynamic Expanding Lists--glad that's over (AGAIN)

  Posted by , 30 April 2012 - - - - - - · 1,562 views
One of the GUI elements I wanted for Titan Trivia was an expandable list for the Trivia question categories and subcategories. Easy enough to do, or so I thought. All the example code that I found online and in my texts were filled with pre-defined data. In other words, you had to know beforehand what your parent and child elements were going to be and hard code them in. I needed something a little more flexible, because my parent and child elements were changing regularly. After more consternation over the code than I'd care to admit, I finally got my expandable lists reading and displaying the trivia question categories and subcategories without me having to hard code ahead of time.

Figuring out how to do that was frustrating at times, but of course satisfying when I finished. I decided to put together a quick 'how to' in case there are others who find they may want to do the same thing. I have no doubt there are more elegant ways of implementing what I have here, but at the very least I know this code works. Instead of pulling out the code I've implemented in Titan Trivia, yesterday I sat down and put together a quick app that demonstrates the functionality.

The app is called "TopicNotes", and it does what it sounds like. It lets you write a note with a topic. If you write another note with the same Topic, it will file that note under the same Parent list header, as in this screenshot:

Posted Image

The interface is simple. Just a single button and an expandable list below it. When you click the button, you get a dialog box:

Posted Image

When you click OK, the topic you just entered a note for goes to the top of your list on the main screen:

Posted Image

Yes, I know this isn't pretty, and there are some glaring omissions in the app (for example, there's no delete function). I may add to it over time, but for now, I just want to demo the dynamic expandable list code.

First, you'll need to override the BaseExpandableListAdapter. Depending on your skill level, this may sound intimidating (I admit I was a bit put off when someone casually suggested it), but it's not that hard for what we're doing here (there are several variations of this to be found online, but if you want to see the code I used for this example, you can find it here: http://numberedmount...overriding.html). I may write a comprehensive tutorial to cover this part as well if there's interest, but for now I'll stay focused.

So, into the main Activity file (TopicNotesActivity.java) I write a function to return an instance of the modified adapter. Note that it calls two additional methods: getAllTopics() and getAllTopicNotes() that return a String array and a 2-dimensional String array respectively. These arrays are required by the ModifiedExpandableListAdapter instance. The Topics and Notes are saved away in a SQLite3 database table.

[source lang="java"][size=2] private ModifiedExpandableListAdapter getAllTopicNotes(){ String[] topics=getAllTopics(); String[][] contents = getAllNotes(topics); ModifiedExpandableListAdapter adapter=new ModifiedExpandableListAdapter(this,topics,contents); return adapter; } private String[] getAllTopics(){ String[] topics=null; int index=0; int size=0; SQLiteDatabase db = topic_notes_data.getReadableDatabase(); Cursor cursor = db.query(TOPICNOTES_TABLE, FROM, null, null, TOPIC, null, ORDER_BY); size = cursor.getCount(); topics = new String[size]; while(cursor.moveToNext()){ if(cursor.getString(1).length()>0){ topics[index]=cursor.getString(1); index++; } } cursor.close(); return topics; } private String[][] getAllNotes(String[] topics){ String[] temp={}; String[][] notes=null; int index=0; //int size=topics.length; notes = new String[topics.length][]; SQLiteDatabase db = topic_notes_data.getReadableDatabase(); for(int i=0;i<topics.length;i++){ int topicsize=0; index=0; Cursor cursor = db.query(TOPICNOTES_TABLE, FROM, "TOPIC=?", new String[]{topics[i]}, null, null, null); topicsize=cursor.getCount(); temp = new String[topicsize]; while(cursor.moveToNext()){ temp[index] = cursor.getString(2); index++; } cursor.close(); notes[i]=temp; } return notes; }[/size][/source]

Now that these methods are written, I can implement them in the activity onCreate:
[source lang="java"][size=2]@Override public void onCreate(Bundle savedInstanceState) { [/size] [size=2]super.onCreate(savedInstanceState); [/size] [size=2]setContentView(R.layout.main); [/size] [size=2]topic_notes_data = new TopicNotesData(this); [/size] [size=2]final Button btnAddTopicNote = (Button) findViewById(R.id.Button_AddTopicNote); [/size] [size=2]btnAddTopicNote.setOnClickListener(new View.OnClickListener() { [/size] [size=2]@Override public void onClick(View v) { [/size] [size=2]showDialog(ADD_TOPIC_NOTE_DLG_ID); [/size] [size=2]} [/size] [size=2]}); [/size] [size=2]//Here we assign the ExpandableListView we defined in our xml file to the code [/size] [size=2]ExpandableListView list = (ExpandableListView)findViewById(R.id.ExpList_Topics); [/size] [size=2]list.setGroupIndicator(null); [/size] [size=2]list.setChildIndicator(null); [/size] [size=2]// Now we fill the Expandable list with the Topics and Notes, using the Modified adapter [/size] [size=2]list.setAdapter(getAllTopicNotes()); [/size][size=2]}[/size][/source]
Last thing, here's the code snippet from the onCreateDialog method that saves new Topics and Notes to the SQLite3 database:
[source lang="java"][size=2]@Override public void onClick(DialogInterface dialog, int which) { EditText topicText = (EditText)layout.findViewById(R.id.EditText_Topic); String strTopic = topicText.getText().toString(); EditText noteText = (EditText)layout.findViewById(R.id.EditText_Note); String strNote = noteText.getText().toString(); SQLiteDatabase db = topic_notes_data.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(TOPIC, strTopic); values.put(NOTE, strNote); db.insertOrThrow(TOPICNOTES_TABLE, null, values); db.close(); ExpandableListView list = (ExpandableListView)findViewById(R.id.ExpList_Topics); list.setGroupIndicator(null); list.setChildIndicator(null); list.setAdapter(getAllTopicNotes()); TopicNotesActivity.this.removeDialog(ADD_TOPIC_NOTE_DLG_ID); }[/size][/source]
That's about it--hopefully this is useful. I left out all the supporting xml files and database files to focus on implementation. TopicNotes is a simple program, but has been fun to work on so far. As I stated above, I may take some time to improve it if for no other reason than to write some useful tutorials for beginner Android programmers. Any feedback is welcome. Thanks!


Just finished a program...to help finish a program

  Posted by , 26 April 2012 - - - - - - · 693 views

Several years ago, when I first started to explore the idea of game programming, I picked up a copy of Real Time Strategy Game Programming Using Direct X 6.0, by Mickey Kawick. I was fairly new to programming, and at the time RTSGP was a bit advanced for me in places, though I did pick up some really good pointers about game creation as a whole. I believe that was the first book I had read that mentioned the idea of creating a utility program to help with the more meticulous tasks of game creation.

In the case of my current project, Titan Trivia, it became apparent soon after I began writing the first questions that the game required more than just question-answer pairs. I needed to track categories, sub-categories, answer tags, difficulty ratings, and many other pieces of data that I hadn't at first considered. Writing them into a flat file wasn't an option, and using a spreadsheet wasn't that much more appealing. I probably could've used a database program of some kind, but in the I decided to write up a custom program to do the job myself. That way I could be sure it did everything I wanted it to do. I used Visual C# 2008, and ended up having almost as fun writing it as I did writing the game itself.

Posted Image

Anyway, I wrote the program to save to a the data to a SQL table. I'm not overly savvy with databases, and needed the questions ultimately dumped to the sqlite3 database for an Android game. Instead of doing any converting, I chose to export the table to an XML file, and in turn import the XML (on a one-time basis) into the sqlite3 database for the game.

No doubt there are other, better ways to do this, but it was fun putting it together, and I learned a lot. Now, to get to the real task at hand, and start writing trivia questions!