<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3883302550302726991</id><updated>2024-08-30T21:29:57.216-07:00</updated><category term="android"/><category term="java"/><category term="activity"/><category term="custom"/><category term="database"/><category term="intent"/><category term="jcomponent"/><category term="joptionpane"/><category term="log"/><category term="serializable"/><category term="sqlite"/><title type='text'>SprogCoder</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sprogcoder.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3883302550302726991/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://sprogcoder.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Nick</name><uri>http://www.blogger.com/profile/01853433374727516546</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>5</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3883302550302726991.post-5613203925714628423</id><published>2012-06-24T16:28:00.000-07:00</published><updated>2019-03-18T07:05:00.129-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="activity"/><category scheme="http://www.blogger.com/atom/ns#" term="android"/><category scheme="http://www.blogger.com/atom/ns#" term="database"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="sqlite"/><title type='text'>Android SQLite Database Design Pattern - Extensible, Blocking and Simple</title><content type='html'>This post is in response to my need to have an Android Database that will:
&lt;br/&gt;&lt;br/&gt;
A) Never ever get into an illegal state, i.e. errors occur if you create/write/read tables at the same time.&lt;br/&gt;
B) Split up management of Database tables by creating classes for each one, but still using one single Database.&lt;br/&gt;
C) Reuse common Database functionality by creating helper methods.&lt;br/&gt;
D) Works at least in Android 2.1+.&lt;br/&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br/&gt;

Here is that solution - tested using multiple threads. I use a global application context to create the database, namely &#39;MyApplication.java&#39; which is copied at the bottom of this post.&lt;br/&gt;&lt;br/&gt;

&lt;b&gt;AbstractDBAdapter.java&lt;/b&gt; - Base class holding Database and helper methods.
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;
public class AbstractDBAdapter
{

   private static final String DB_NAME = &quot;CountriesDatabase&quot;;
   private static final String DB_TAG = &quot;Countries Database Tag&quot;;
   private static final int DB_VERSION = 1;
   
   private volatile static DatabaseHelper mDbHelper;
   
   private static final Object lock = new Object();

   protected static final String COUNTRIES_TABLE_NAME = &quot;CountriesTable&quot;;
   private static final String COUNTRIES_TABLE_CREATE = &quot;CREATE TABLE &quot; + COUNTRIES_TABLE_NAME
         + &quot; (COUNTRY_NAME TEXT, COUNTRY_CAPITAL TEXT);&quot;;
   private static final String COUNTRIES_TABLE_DROP = &quot;DROP TABLE IF EXISTS &quot; + COUNTRIES_TABLE_NAME + &quot;;&quot;;

   /**
    * Constructor - takes the context to allow the Database to be opened/created
    * 
    * @param context the Context within which to work
    */
   protected AbstractDBAdapter(Context context)
   {
      if (mDbHelper == null)
      {
         synchronized (AbstractDBAdapter.class)
         {
            if (mDbHelper == null)
            {
               if (context == null)
               {
                  throw new RuntimeException(&quot;Context is null!&quot;);
               }
               mDbHelper = new DatabaseHelper(context);
            }
         }
      }
   }

   /**
    * Helper Methods
    */
   private Cursor getCursor(String tableName, String args)
   {
      String SQL_STATEMENT = &quot;&quot;;
      if (args != null)
      {
         SQL_STATEMENT = &quot;SELECT * FROM &quot; + tableName + &quot; WHERE &quot; + args;
      }
      else
      {
         SQL_STATEMENT = &quot;SELECT * FROM &quot; + tableName;
      }
      Cursor c = mDbHelper.getReadableDatabase().rawQuery(SQL_STATEMENT, null);
      return c;
   }

   protected String getString(String tableName, String args, String columnIndex)
   {
      synchronized (lock)
      {
         String text = &quot;&quot;;
         Cursor c = getCursor(tableName, args);
         if (c.moveToFirst())
         {
            text = c.getString(c.getColumnIndex(columnIndex));
         }
         c.close();
         mDbHelper.getReadableDatabase().close();
         return text;
      }
   }

   protected String insertRow(String tableName, ContentValues cv)
   {
      synchronized (lock)
      {
         long result = mDbHelper.getWritableDatabase().insertOrThrow(tableName, null, cv);
         mDbHelper.getWritableDatabase().close();
         if (result == -1)
         {
            // String stringResult = (result == -1) ? &quot;Row Already Exists&quot; : &quot;Row Added&quot;;
         }
         return Long.toString(result);
      }
   }
   
   /**
    * Internal Database
    */
   private static class DatabaseHelper extends SQLiteOpenHelper
   {

      DatabaseHelper(Context context)
      {
         super(context, DB_NAME, null, DB_VERSION);
         Log.v(DB_TAG, &quot;DatabaseHelper() - Database &quot; + DB_NAME + &quot; Ready - Version: &quot; + DB_VERSION);
      }

      @Override
      public void onCreate(SQLiteDatabase db)
      {
         db.execSQL(COUNTRIES_TABLE_CREATE);
         Log.v(DB_TAG, &quot;onCreate() - Created New Database - DatabaseName: &quot; + DB_NAME);
      }

      @Override
      public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
      {
         db.execSQL(COUNTRIES_TABLE_DROP);
         onCreate(db);
         Log.v(DB_TAG, &quot;onUpgrade() - Upgrading Database - DatabaseName: &quot; + DB_NAME);
      }
   }

}
&lt;/pre&gt;


&lt;b&gt;DBAdapterCountry.java&lt;/b&gt; - Class that manages the table &#39;CountriesTable&#39;. Extends AbstractDBAdapter.java.
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;
public class DBAdapterCountry extends AbstractDBAdapter
{

   /**
    * Singleton Instance Creation
    */
   private volatile static DBAdapterCountry INSTANCE;

   static DBAdapterCountry getInstance()
   {
      if (INSTANCE == null)
      {
         synchronized (DBAdapterCountry.class)
         {
            if (INSTANCE == null)
            {
               INSTANCE = new DBAdapterCountry(MyApplication.getAppContext());
            }
         }
      }
      return INSTANCE;
   }

   private DBAdapterCountry(Context context)
   {
      super(context);
   }

   /**
    * Class
    */
   public void addCountry(String countryName, String countryCapital)
   {
      ContentValues cv = new ContentValues();
      cv.put(&quot;COUNTRY_NAME&quot;, countryName);
      cv.put(&quot;COUNTRY_CAPITAL&quot;, countryCapital);
      insertRow(COUNTRIES_TABLE_NAME, cv);
   }

   public String getCountryCapital(String countryName)
   {
      String args = &quot;COUNTRY_NAME=&#39;&quot; + countryName + &quot;&#39;&quot;;
      return getString(COUNTRIES_TABLE_NAME, args, &quot;COUNTRY_CAPITAL&quot;);
   }
   
}
&lt;/pre&gt;

&lt;b&gt;DatabaseActivity.java&lt;/b&gt; - Activity used to test the Database.
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;
public class DatabaseActivity extends Activity
{
   @Override
   public void onCreate(Bundle savedInstanceState)
   {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      
      // Thread 1 
      Thread thread1 = new Thread(new Runnable()
      {
         public void run()
         {
            DBAdapterCountry.getInstance().addCountry(&quot;England&quot;, &quot;London&quot;);
            Log.v(&quot;MyTag&quot;, DBAdapterCountry.getInstance().getCountryCapital(&quot;England&quot;));
         }
      });
      
      // Thread 2
      Thread thread2 = new Thread(new Runnable()
      {
         public void run()
         {
            DBAdapterCountry.getInstance().addCountry(&quot;France&quot;, &quot;Paris&quot;);
            Log.v(&quot;MyTag&quot;, DBAdapterCountry.getInstance().getCountryCapital(&quot;France&quot;));
         }
      });
      
      // Thread 3
      Thread thread3 = new Thread(new Runnable()
      {
         public void run()
         {
            DBAdapterCountry.getInstance().addCountry(&quot;Spain&quot;, &quot;Madrid&quot;);
            Log.v(&quot;MyTag&quot;, DBAdapterCountry.getInstance().getCountryCapital(&quot;Spain&quot;));
         }
      });

      thread1.start();
      thread2.start();
      thread3.start();
   }
}
&lt;/pre&gt;

&lt;b&gt;MyApplcation.java&lt;/b&gt; - Started when application is loaded - contains global application context. The line &lt;code&gt;android:name=&quot;.MyApplication&lt;/code&gt; also needs to be added in your AndroidManifest.xml to make it start when your application starts.
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;
public class MyApplication extends Application
{

   private static Context context;

   public void onCreate()
   {
      super.onCreate();
      MyApplication.context = getApplicationContext();
   }

   public static Context getAppContext()
   {
      return context;
   }

}
&lt;/pre&gt;
If you stick to this pattern of Database creation you can simply add a new adapter class, along with a create/drop SQL statement whenever you want to add a new table. And if you need any other helper methods like &lt;code&gt;getInt&lt;/code&gt; you can add them to AbstractDBAdapter.java. 
&lt;br/&gt;&lt;br/&gt;
I believe this approach makes Database code management a lot simpler, cohesive, cuts down lines of code and most importantly does not cause the Database to get into an illegal state.
&lt;br/&gt;&lt;br/&gt;
Any comments on this approach are welcome! :)
&lt;br/&gt;</content><link rel='replies' type='application/atom+xml' href='http://sprogcoder.blogspot.com/feeds/5613203925714628423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sprogcoder.blogspot.com/2012/06/android-sqlite-database-design-pattern.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3883302550302726991/posts/default/5613203925714628423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3883302550302726991/posts/default/5613203925714628423'/><link rel='alternate' type='text/html' href='http://sprogcoder.blogspot.com/2012/06/android-sqlite-database-design-pattern.html' title='Android SQLite Database Design Pattern - Extensible, Blocking and Simple'/><author><name>Nick</name><uri>http://www.blogger.com/profile/01853433374727516546</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3883302550302726991.post-5519194631595981471</id><published>2012-01-16T09:33:00.000-08:00</published><updated>2019-03-18T07:05:00.011-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="activity"/><category scheme="http://www.blogger.com/atom/ns#" term="android"/><category scheme="http://www.blogger.com/atom/ns#" term="intent"/><category scheme="http://www.blogger.com/atom/ns#" term="serializable"/><title type='text'>Android Intents - Passing Serializable Custom Objects to an Activity</title><content type='html'>The passing of custom objects to an &lt;a href=&quot;http://developer.android.com/reference/android/app/Activity.html&quot; target=&quot;_blank&quot;&gt;Activity&lt;/a&gt; using&amp;nbsp;&lt;a href=&quot;http://developer.android.com/reference/android/content/Intent.html&quot; target=&quot;_blank&quot;&gt;Intents&lt;/a&gt;&amp;nbsp;can seem very confusing - honestly I never quite worked out how to use&amp;nbsp;&lt;a href=&quot;http://developer.android.com/reference/android/os/Parcelable.html&quot; target=&quot;_blank&quot;&gt;Parcelable&lt;/a&gt;. It seemed like a lot of code for passing a custom object to one of my&amp;nbsp;activities. The method of passing objects I settled for was one that required the least amount of code and did the job.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;That method is to implement &lt;a href=&quot;http://docs.oracle.com/javase/1.5.0/docs/api/java/io/Serializable.html&quot; target=&quot;_blank&quot;&gt;Serializable&lt;/a&gt; for the object&#39;s class you want to pass to an activity. Then simply pass that serialized object into the intent and grab it when the activity is started. This stackoverflow &lt;a href=&quot;http://stackoverflow.com/questions/3611843/is-using-serializable-in-android-bad&quot; target=&quot;_blank&quot;&gt;question&lt;/a&gt;&amp;nbsp;does point out its downfalls however, so &lt;u&gt;beware&lt;/u&gt;, the most important downfalls for me would be that its slow and can cause increased gc activity. I promise I will spend time with Parcelable and write a blog post on it, and make it as easy as possible to understand!&lt;br /&gt;
&lt;br /&gt;
Here is our custom object we are going to pass to another activity, notice it &lt;b&gt;implements&amp;nbsp;Serializable&lt;/b&gt;, this is very important as when we use&amp;nbsp;&lt;code&gt;putExtra(String name, Serializable value)&lt;/code&gt;&amp;nbsp;in our intent it takes a Serializable parameter.
&lt;br /&gt;
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;import java.io.Serializable;

public class Present implements Serializable
{

 private final String text;

 public Present(String text)
 {
  this.text = text;
 }

 public String getText()
 {
  return text;
 }

}
&lt;/pre&gt;
Now in the activity class where you start another activity using an intent, use this code.
&lt;br /&gt;
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;Present myPresent = new Present (&quot;Red Bike&quot;);
Intent intent = new Intent(this, SecondActivity.class); // replace with own Activity class
intent.putExtra(&quot;present&quot;, myPresent);
startActivity(intent);
&lt;/pre&gt;
From the &#39;SecondActivity&#39; class you can get the object back by doing this:
&lt;br /&gt;
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;Intent intent = getIntent();
Present myPresent = (Present)intent.getSerializableExtra(&quot;present&quot;);
Log.v(&quot;Tag&quot;, &quot;My Present is: &quot; + myPresent.getText());
&lt;/pre&gt;
Now you should be able to send and receive custom objects to other activities!</content><link rel='replies' type='application/atom+xml' href='http://sprogcoder.blogspot.com/feeds/5519194631595981471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sprogcoder.blogspot.com/2012/01/android-intents-passing-serializable.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3883302550302726991/posts/default/5519194631595981471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3883302550302726991/posts/default/5519194631595981471'/><link rel='alternate' type='text/html' href='http://sprogcoder.blogspot.com/2012/01/android-intents-passing-serializable.html' title='Android Intents - Passing Serializable Custom Objects to an Activity'/><author><name>Nick</name><uri>http://www.blogger.com/profile/01853433374727516546</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3883302550302726991.post-5739644273250451479</id><published>2012-01-12T09:11:00.000-08:00</published><updated>2019-03-18T07:05:00.249-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="android"/><category scheme="http://www.blogger.com/atom/ns#" term="custom"/><category scheme="http://www.blogger.com/atom/ns#" term="log"/><title type='text'>Android Custom Logging - Enable/Disable Logs</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
Part of the Android &#39;Preparing for Release&#39; onto the Android Market is to remove all &lt;a href=&quot;http://developer.android.com/reference/android/util/Log.html&quot; target=&quot;_blank&quot;&gt;Log&lt;/a&gt;&amp;nbsp;messages and have the &lt;code&gt;android:debuggable=&quot;false&quot;&lt;/code&gt; in the manifest file. This is outlined &lt;a href=&quot;http://developer.android.com/guide/publishing/preparing.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;&amp;nbsp;in the section called &#39;Turn off logging and debugging&#39;.&lt;br /&gt;
&lt;br /&gt;
Removing all logs can be difficult, however you might still decide, that&#39;s okay I will comment all my logs out! This would not be a bad idea but its not the most efficient by far, an alternative is to add &#39;if&#39; statements for every Log in your app that points to a global boolean flag...however that is also not easy with lots of Log calls.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;The solution that I adopted was create a wrapper class around the Log class called MyLog. Then by replacing all instances of Log in my Android app with MyLog, I was then able to have an &#39;on off&#39; switch for Log calls...the code looked a little bit like this:&lt;br /&gt;
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;import android.util.Log;

public class MyLog
{
 
 private MyLog()
 {
  
 }

 private static boolean LOG_ENABLED = true;

 public static void d(String tag, String msg)
 {
  if (LOG_ENABLED)
   Log.d(tag, msg);
 }
 
 public static void d(String tag, String msg, Throwable tr)
 {
  if (LOG_ENABLED)
   Log.d(tag, msg, tr);
 }

 public static void e(String tag, String msg)
 {
  if (LOG_ENABLED)
   Log.e(tag, msg);
 }

 public static void e(String tag, String msg, Throwable tr)
 {
  if (LOG_ENABLED)
   Log.e(tag, msg, tr);
 }

 public static void i(String tag, String msg)
 {
  if (LOG_ENABLED)
   Log.i(tag, msg);
 }

 public static void i(String tag, String msg, Throwable tr)
 {
  if (LOG_ENABLED)
   Log.i(tag, msg, tr);
 }
 
 public static void v(String tag, String msg)
 {
  if (LOG_ENABLED)
   Log.v(tag, msg);
 }
 
 public static void v(String tag, String msg, Throwable tr)
 {
  if (LOG_ENABLED)
   Log.v(tag, msg, tr);
 }
 
 public static void w(String tag, Throwable tr)
 {
  if (LOG_ENABLED)
   Log.w(tag, tr);
 }
 
 public static void w(String tag, String msg, Throwable tr)
 {
  if (LOG_ENABLED)
   Log.w(tag, msg, tr);
 }

 public static void w(String tag, String msg)
 {
  if (LOG_ENABLED)
   Log.w(tag, msg);
 }
 
}
&lt;/pre&gt;
Example Log from MyLog:&lt;br /&gt;
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;MyLog.v(&quot;Tag&quot;,&quot;Hello World!&quot;);
&lt;/pre&gt;
As you may have guessed to turn the logs off you change the code to &lt;code&gt;LOG_ENABLED = false&lt;/code&gt;, this allows you to easily switch between development and publishing versions of the code.</content><link rel='replies' type='application/atom+xml' href='http://sprogcoder.blogspot.com/feeds/5739644273250451479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sprogcoder.blogspot.com/2012/01/android-custom-logging-enabledisable.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3883302550302726991/posts/default/5739644273250451479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3883302550302726991/posts/default/5739644273250451479'/><link rel='alternate' type='text/html' href='http://sprogcoder.blogspot.com/2012/01/android-custom-logging-enabledisable.html' title='Android Custom Logging - Enable/Disable Logs'/><author><name>Nick</name><uri>http://www.blogger.com/profile/01853433374727516546</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3883302550302726991.post-7085181506885180419</id><published>2011-10-23T02:34:00.000-07:00</published><updated>2019-03-18T07:05:00.368-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="joptionpane"/><title type='text'>Java Message Box (Alert Popup)</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
A simple alternative to printing out messages in the console, this code will popup a message box in Java similar to that of Javascript &lt;code&gt;alert(&quot;hello&quot;)&lt;/code&gt;. &lt;br /&gt;
&lt;br /&gt;
The code can be modified to include several types of message box&amp;nbsp;types such as an error icon or different button options. Have a look &lt;a href=&quot;http://download.oracle.com/javase/6/docs/api/javax/swing/JOptionPane.html&quot;&gt;JOptionPane&lt;/a&gt; in the JavaDoc&#39;s for more information&amp;nbsp;on these.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;import javax.swing.JOptionPane;

/**
 * Displays a popup message box in Java
 */
public class MessageBox
{

  /**
   * Displays a popup message box with the Information Message icon and button &quot;Okay&quot;
   * 
   * @param message the message to display in the popup
   */
   public static void MessageBoxOkayInfo(String message)
   {
     JOptionPane.showMessageDialog(null, message, &quot;Alert&quot;,
     JOptionPane.INFORMATION_MESSAGE);
   }
}&lt;/pre&gt;
&lt;br /&gt;
To try this code use this snippet.&lt;br /&gt;
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;MessageBox.MessageBoxOkayInfo(&quot;Hello World!&quot;);&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://sprogcoder.blogspot.com/feeds/7085181506885180419/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sprogcoder.blogspot.com/2011/10/java-message-box-alert-popup.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3883302550302726991/posts/default/7085181506885180419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3883302550302726991/posts/default/7085181506885180419'/><link rel='alternate' type='text/html' href='http://sprogcoder.blogspot.com/2011/10/java-message-box-alert-popup.html' title='Java Message Box (Alert Popup)'/><author><name>Nick</name><uri>http://www.blogger.com/profile/01853433374727516546</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3883302550302726991.post-3415499254588556083</id><published>2011-10-10T13:21:00.000-07:00</published><updated>2019-03-18T07:04:59.829-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="custom"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="jcomponent"/><title type='text'>Java Custom Component - Colored Progress Bar</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://3.bp.blogspot.com/-yjTBhOMTeQM/TxGng6sOQiI/AAAAAAAAAMY/uaVmK6cVSdg/s1600/progressbar3.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-yjTBhOMTeQM/TxGng6sOQiI/AAAAAAAAAMY/uaVmK6cVSdg/s1600/progressbar3.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
After getting slightly bored of the standard Java components available to me I decided to spice things up a little. I wanted to be able to have a clean, colourful and customizable progress bar. I also wanted the progress bar to be able to change colour at certain values, such as when it reaches a low percent&amp;nbsp;it will go&amp;nbsp;red.&lt;br /&gt;
&lt;br /&gt;
Essentially I extend &lt;a href=&quot;http://download.oracle.com/javase/6/docs/api/javax/swing/JComponent.html&quot;&gt;JComponent&lt;/a&gt; and use &lt;a href=&quot;http://download.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#paintComponent%28java.awt.Graphics%29&quot;&gt;paintComponent&lt;/a&gt; method which is called automatically by Java to draw the progress bar.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;This code can be easily extended and customized to change/add more colours as well as editing the percentages of the bar as to when it will change colour&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;

import javax.swing.JComponent;

public class ProgressBarColored extends JComponent
{

 private static final long serialVersionUID = 1L;

 private Rectangle clipRect = new Rectangle(); // creating new rectangular area to draw on

 private double accuracy = 100; // how accurately the progress bar is drawn
 private double percentage; // progress bar percentage (%)
 private double maximumValue = 100; // maximum value of progress bar
 private double value = 0; // value of progress bar

 private volatile Color backgroundColor = Color.black; // background color of progress bar
 
 private volatile Color foregroundColor;
 private Color startColor = new Color(0, 255, 0); // green color when progress bar is high %
 private Color middleColor = new Color(255, 255, 0); // yellow color when progress bar is medium %
 private Color endColor = new Color(204, 0, 0); // red color when progress bar is low %

 private int hPadding = 10; // horizontal padding
 private int vPadding = 10; // vertical padding

 /**
  * 
  * Creates a new ProgressBarColored with a maximum value and initial starting value
  * 
  * @param maximumValue
  * @param initialValue
  */
 public ProgressBarColored(final int maximumValue, int initialValue)
 {
  this.maximumValue = maximumValue;
  this.value = initialValue;
  this.setDoubleBuffered(true);
  setValue(value);
 }

 
 protected void paintComponent(Graphics g)
 {
  accuracy = getWidth() / maximumValue;

  g.getClipBounds(clipRect); // get progress bar&#39;s drawing area
  Graphics2D g2d = (Graphics2D) g.create(); // create Graphics2D object based on clipped graphics area
 
  g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // setting rendering hints
  
  drawBackground(g2d); // draw progress bar background
  drawForground(g2d); // draw progress bar progress graphic in foreground
  
  g2d.dispose(); // clean up
 }


 private void drawBackground(Graphics2D g2d)
 {
  g2d.setColor(backgroundColor);
  g2d.fillRect(hPadding/2, vPadding/2, getWidth() - hPadding , getHeight() - vPadding);
 }

 private void drawForground(Graphics2D g2d)
 {
  g2d.setColor(foregroundColor);
  g2d.fillRect(hPadding/2, vPadding/2, (int) ((getWidth() - hPadding) / ((maximumValue * accuracy) / (value * accuracy))), getHeight() - vPadding);
 }

 /**
  * 
  * Sets the value of the progress bar and automatically assigns the color of it
  * 
  * @param newValue
  */
 public void setValue(double newValue)
 {
  value = newValue;
  accuracy = getWidth() / maximumValue;
  percentage = ((getValue() * 1.0) / getMaximum()) * 100;
  if (percentage == 100) // when between 40% and 100%
  {
   setForeground(startColor);
  }
  else if (percentage &amp;gt;= 20 &amp;amp;&amp;amp; percentage &amp;lt; 40) // when between 20% and 40%
  {
   setForeground(middleColor);
  }
  else if (percentage &amp;gt;= 0 &amp;amp;&amp;amp; percentage &amp;lt; 20) // when between 0% and 20%
  {
   setForeground(endColor);
  }
  repaint();
 }
 
 public double getValue()
 {
  return value;
 }

 public void setMaximum(double newMaximumValue)
 {
  maximumValue = newMaximumValue;
  repaint();
 }
 
 public double getMaximum()
 {
  return maximumValue;
 }

 @Override
 public void setForeground(Color color)
 {
  this.foregroundColor = color;
 }
 
 @Override
 public Color getForeground()
 {
  return foregroundColor;
 }

 @Override
 public void setBackground(Color color)
 {
  this.backgroundColor = color;
 }

 @Override
 public Color getBackground()
 {
  return backgroundColor;
 }
 
 @Override
 public Dimension getPreferredSize()
 {
  return new Dimension(100, 30);
 }
 
 @Override
 public Dimension getMinimumSize()
 {
  return new Dimension(10, 5);
 }

}
&lt;/pre&gt;
&lt;br /&gt;
Here is some example code that will enable you to test the component using a timer decreasing from 100 to 0. Copy and paste this code somewhere in a gui to test it out.&lt;br /&gt;
&lt;pre class=&quot;prettyprint lang-java&quot;&gt;...
ProgressBarColored progressBarColored = new ProgressBarColored(100, 100);
...
for (int i = 0; i &amp;lt;= 100; i++)
{
 try
 {
  Thread.sleep(50);
  progressBarColored.setValue(100 - i);
 }
 catch (InterruptedException e)
 {
  e.printStackTrace();
 }
}&lt;/pre&gt;
&lt;br /&gt;
Below is a screenshot of the progress bar within an interface with a low percentage, the percent is between 20 and 40 percent so the color is yellow.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://4.bp.blogspot.com/-XIQzp3clh_w/TpNR2N1OjCI/AAAAAAAAAHM/7OG2jEujuV8/s1600/progress%2Bbar%2Bcolored%2Bexample.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;80&quot; src=&quot;http://4.bp.blogspot.com/-XIQzp3clh_w/TpNR2N1OjCI/AAAAAAAAAHM/7OG2jEujuV8/s320/progress%2Bbar%2Bcolored%2Bexample.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Any feedback or questions are welcome!</content><link rel='replies' type='application/atom+xml' href='http://sprogcoder.blogspot.com/feeds/3415499254588556083/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sprogcoder.blogspot.com/2011/10/custom-java-component-colored-progress.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3883302550302726991/posts/default/3415499254588556083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3883302550302726991/posts/default/3415499254588556083'/><link rel='alternate' type='text/html' href='http://sprogcoder.blogspot.com/2011/10/custom-java-component-colored-progress.html' title='Java Custom Component - Colored Progress Bar'/><author><name>Nick</name><uri>http://www.blogger.com/profile/01853433374727516546</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-yjTBhOMTeQM/TxGng6sOQiI/AAAAAAAAAMY/uaVmK6cVSdg/s72-c/progressbar3.png" height="72" width="72"/><thr:total>0</thr:total></entry></feed>