Friday 30 December 2011

Goodbye 2011... Hello 2012

As the end of this year is rapidly approaching, I thought I would take the opportunity to assess a few things and work out what changes I plan to make for next year.

Changes I have come up with so far are:

Shave more often.

My wife hates me having a beard or stubble, and I don't blame her, so I will attempt to shave every day. Not saying I will manage it, but I plan to try.

Finish what I start.

I am fantastic at coming up with new projects and starting them off, but I am one of the worst at getting my own finished. I have about five or six half finished programs sitting on my hard drive, as well as some poetry I started, but got bored with and some stories. Hell, if I get good at this 'finishing stuff' thing, I might even get around to that novel I promised myself to write years ago (but don't hold your breath on that one).

Learn something new.

2012 is the year I get off my backside and learn something. Something totally unrelated to computers and programming. I may even take a course, if I can find the right one and I can afford it.

Quit smoking.

This time, I am going to do it. I spend far too much money, only to set fire to it and inhale. I'm also getting to that age where I really should be thinking about my health a bit more. Which brings me on to...

Lose weight.

Somehow, over the last few years, I have managed to pile on a few too many pounds. Well, enough is enough, it has to go.

I think that's enough to get started, I don't want to over-do it. I do plan to get some more tutorials written too, so hopefully you will find something a little more interesting that my plans for the future.

As I will also be tackling some of my programming projects, most I will be restarting from scratch, I hope to be able to keep everyone apprised of the progress of these too.

Anyhow, I will be seeing the new year in with my family, so, as I won't be writing anything else here again until next year...

 

Happy New Year

Wednesday 28 December 2011

What have developers got against Mac users?

Just a quick rant about the software industry. In particular, the Mac software industry.

I switched to  Mac back in 2006 and have never looked back. I like the system, the security, the ease of use and maintenance, the build quality, etc. I could probably go on for hours (but I won't).

However, there is one thing that being a Mac user has caused me concern.

Whenever a new version of the OS is released, it appears that developers are almost chomping at the bit to release their software for the new OS. I can understand this if they were taking advantage of the new features of the operating system, some 'whizz-bang' thing that has only just been introduced, but most of the time, they are not. Most of the time, it just appears that the developers are compiling for OSX 10.whatever just for the sake of it.

I find it somewhat frustrating when I find some piece of software that I would like, only to find that it is only available for the latest version of Apple's operating system. Yet, if you look at the Windows requirements, 9 out of 10 times, it will run on Windows XP, an operating system that is over 10 years old!

When I worked in the Windows software industry, one of the prime directives was to make sure you did not alienate those users with older operating systems, and therefore a sizeable chunk of your market. This philosophy does not seem to cross the OS border into Mac. Why not?

It was really brought home to me recently when I saw that Doom 3 had been reduced to a little over £6. I was amazed and overjoyed. I originally played the Demo of Doom 3 on my G5 Mac, running OS X 10.4, so the assumption that it would run ok on my Intel Mac, with 10.5.8, seemed logical. But then I checked the requirements. For some bizarre reason, Aspyr (I'm not picking on them, just using them as an example) have decided that they would recompile Doom 3 to an Intel only application, and in doing so, have increased the required operating system to OS X 10.6.

Now, I understand that this may be to get the game on the App Store, but is it really necessary to cut out a large slice of users? Maybe I should be looking at why Apple decided to make the App Store require 10.6?

Either way, I think it is definitely a problem with the Mac software industry somewhere. Not everyone wants to upgrade to the latest OS. My Windows machine is still running Windows XP, and I don't see me upgrading it for a few years yet. I'm not going to abandon my Mac, in fact I think I'll probably have to go the way most Mac users do and upgrade my OS, just to allow me to run certain software.

I for one, will not be compiling my software for the latest OS. I aim my software at the lowest possible requirement to allow as many people the benefit of using it as possible. I know of a number of others that also go this route, and I salute them.

So, come on developers, you're in the business of making money, so why alienate your customers?

Wednesday 21 December 2011

Comment About Comments

After posting my last tutorial, someone made a criticism, or rather an observation, about the coding style I have been using. I will be the first to admit, they are quite right in what they said, too.

I failed to use any comments in my code. I should have commented. No matter how small the piece of code you are writing, it is always advisable to put comments in your code. This can save you a lot of time in the future, especially if you haven't worked with that piece of code for some time. Even one line of code can cause a programmer to stop and think, if it's not too clear on it's function.

So, my apologies to all. From now on, I shall ensure that I place adequate comments in the code, as well as the explanations of the code function in the blogs.

Extending The Date Class

After the positive response I received about my last post (Flipping Pages), I have decided to carry on with some simple tutorials, in the hope that they will be useful to people.
This time, I will be looking at another question that has been posed in the Real Studio forums on more than one occasion. The question is how to determine the last day of any given month.
At it's simplest, I could just write a single method to accomplish this, and it would be perfectly valid. However, RealBasic is an object orientated language and I want to explore a true object orientated approach method for solving the problem.

As I already have a Date class which handles most of the time and date functions, it seems only right that I use this as my base. But, this time, I shall not be creating a subclass of the Date class, this time I shall be extending the class. Extending a class allows me to add methods to an existing class and then use them as if they are defined in the class definition. The advantage of this over a subclass, is that I can still continue to use the Date class with existing classes and methods, with no modifications.
Hopefully, this will become clearer as I progress.

To extend a class, I need only create a new method, in a module. However, the first parameter of that method must be of the class type that I am extending and use the keyword Extends.

First step then, is to create a new module in our project. In the screen shot, I have renamed this module to DateExtensions.

So, to create a method that adds to the Date class and returns the last day of the current month, I declare my new method in DateExtensions thus:


Function LastDayOfMonth(Extends d As Date) As Integer


Another useful thing would be a method that could tell me if the current year of the Date object is a leap year. I mention this now, because I will be using the method in the LastDayOfMonth method. So, the next step is to add another method that extends the Date class. This one will be called IsLeapYear and returns a boolean value.
The declaration of this method is:

Function IsLeapYear(Extends d As Date) As Boolean


Now it is time to add the actual code. I will start with the IsLeapYear method, as that will be used by LastDayOfMonth.

Before I do add the code, I ought to mention something about extending a class. When a method is added to an existing class, by using the Extends keyword, the program can refer to the instance of the class with the first parameter in the parameter list. Hopefully, this will demonstrate.

As you can see, this method only requires one line of code. What the method is returning may look a little daunting at first, but it is actually rather simple. All it does is calculate whether or not the year stored in the object (referred to by the variable d) is divisible by 400 or, the year is divisible by 4, but not divisible by 100.
Therefore, if the year stored in the object is a leap year, then IsLeapYear will return True, otherwise it will return False.

Now I can determine if the year is a leap year, I can now insert the code into LastDayOfMonth:

There are several different ways to determine the last day of the month. The one I have presented here is the one I normally use. I believe it is probably the fastest, although I may be wrong so, please don't flame me. It is also very easy to understand.

I use a simple Select Case condition on the month of the Date object.
If the month is 2 (February), then I know that I need to check if I am in a leap year, so I use the new IsLeapYear method to test this. If I am in a leap year, then return 29, otherwise, February only has 28 days.
The next Case statement tests if the month is one of the following: January, March, May, July, August, October or December. These months all have 31 days, so that is what is returned.
Finally, if neither of the above two Case statements are True, then the month must have 30 days.

That is it. The Date class has now been extended to include two new methods. The methods are used like any other method of the Date class. For Example, the following code creates a For...Next loop for everyday of the current month:

I hope you enjoyed this one, and maybe found it useful.

Monday 19 December 2011

Flipping Pages

I saw in the RealStudio forums that someone wanted to know how to get confirmation to change the page on a PagePanel BEFORE it changed. As there is no way to intercept the Change event before it fires, I thought I would have a crack at solving the issue.

The first step is to create a subclass of the PagePanel. Although we want to change some of the functionality, we still want the majority of the functionality to remain intact, so it makes sense to create a subclass. No need to re-invent the wheel.

Next, we need to add three new event definitions for the class.

CanChange
Change
Open

The Change and Open events are to reintroduce the existing events, because we will need to use them for this subclass.
The other event CanChange is the key to this modification. Ensure that the CanChange event returns a boolean value.

We also need two new private variables. These are an integer variable, called OldPageValue and a boolean variable called DoNotConfirm.

That's it for the setup. Easy right?
Well, now for the hard bit. Well, not really, this class only requires two routines, both of which are located in the event handlers.
First of all, we need to initialise everything. As normal, we do this in the Open event handler and is accomplished with just three lines of code:

The first line simply sets the value of OldPageID to the initial page displayed. Normally, this would be page zero. The next line sets DoNotConfirm to False. This means that we do not want to bypass the Change event.

Now for a slightly trickier piece of code, but still fairly simple:

We put this code in the original Change event of the PagePanel. I shall explain what is happening here line by line:


if not DoNotConfirm Then
If the DoNotConfirm variable is set to False then proceed with this. If the variable is set to True, then we need to ignore this entire routine.

if RaiseEvent CanChange then 
  OldPageID=Value
  RaiseEvent Change
Now, we call the new event handler. If the return value is True, then we want to change the page. As the page has actually already changed, we just store the new value of the PagePanel and then call the new Change event.

else
  DoNotConfirm=True
  Value=OldPageID
  DoNotConfirm=False
If the CanChange event returned False, then we need to return to the previous page. However, we do not want this Change event processing again, so we set the DoNotConfirm variable to True before setting the Value of the PagePanel back to the OldPageID. We also need to reset the DoNotConfirm variable back to False once the Value has been set.

That is it. We now have a new control that we can drag onto our window which will give us a PagePanel that can test to see if the change of page is permitted, either by some internal processing, or user confirmation.

Wednesday 31 August 2011

Little things make a big difference

Just wanted to share this post from Bob Keeney, one of the 'gurus' of RealStudio development:

BKeeney Briefs » Favorite New Feature in 2011 Release 3


If you use graphics a lot in your projects, you’ve probably found Real Studio to be a painful to use at times.  If you changed the graphic file, you would have to reload the project for it to take effect.  If you found that to be a pain too, then 2011 Release 3 contains much goodness for you.


I discovered this today while I was adjusting my window layout.  I decided that my BevelButton icon needed to be 48×48 rather than 32×32.  I had the Window editor still open when I copied the graphic with the same name as the old one into the same location.  A few seconds later the BevelButton updated with the new icon with no actions taken by me.  Yay!


Of course, it’s possible this has been in Real Studio for a couple of releases until now but I’ll give the credit for this release.  Sometimes it’s the little things that make you happy.  :)

Tuesday 30 August 2011

Multithreading in RealStudio - avoiding a common pitfall

I've been working on a new project (more details later), which requires a background thread to perform some processing quite frequently. Everything was going fine and all testing was going great, until I started to increase the amount of data in the application.
Suddenly, things seemed to slow down dramatically. I thought this was  due to too much processing in the paint method of a custom control I had created, so I stripped it down as much as possible, removing a lot of the functionality which I would have to replace later. But, none of this seemed to fix the issue.
After a few days, I realised that there was one area, I had not touched: the background thread.

To cut a long (and quite painful) story short, I had treated the thread as I would have in Delphi, Objective-C or any other language I have used in the past. These other languages allow for true multithreading. RealStudio, does not. Rather than having the OS handle the threading, RealStudio uses it's own thread scheduler.

Turns out the fix was this was very simple. In the loop, within the threads execution, I place the following line:

App.YieldToNextThread

before the end of the loop. This allowed the application to perform other actions required in the main thread.

Wednesday 24 August 2011

Some old, but useful code

Digging through some archives, I found some useful code, so I thought I would share these.

These snippets are from my Delphi programming days, so the code is in Pascal, but it can easily be converted to whichever language is being used.

Hide an application from the taskbar - Delphi

This is a really simple technique that can hide your application from the taskbar.In your main forms On Create event, type the following code:

SetWindowLong(Application.Handle, GWL_EXSTYLE, GetWindowLong(Application.Handle, GWL_EXSTYLE ) or WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW);

That's all there is to it.

Making a program run at Windows startup - Delphi

On your programs Settings or Preferences form, place a TCheckBox with the caption Run at Windows Startup.

In the forms uses clause, include the unit Registry.

In the TCheckBox On Click event, include the following code:

procedure TForm1.TCheckBox1Click(Sender: TObject); 

     var Registry: TRegistry; 

 begin

      Registry := TRegistry.Create; 

      Registry.RootKey := HKEY_LOCAL_MACHINE;

      Registry.OpenKey('Software\Microsoft\Windows\CurrentVersion\Run', false);

      If TCheckBox1.Checked then 

          Registry.WriteString(Application.Title, Application.ExeName) 

      else Registry.DeleteValue(Application.Title); 

      Registry.CloseKey; 

      Registry.free; 

end; 

To ensure that the TCheckBox displays the current status of the function when the form is displayed, we need to insert the following code into the forms On Show event: 

procedure TForm1.FormShow(Sender: TObject); 

    var Registry : TRegistry; 

begin 

    Registry := TRegistry.Create;

    Registry.RootKey := HKEY_LOCAL_MACHINE;

    Registry.OpenKey('Software\Microsoft\Windows\CurrentVersion\Run', false); 

    CheckBox1.Checked := Registry.ValueExists(Application.Title); 

    Registry.CloseKey; 

    Registry.free; 

end;

This code simply checks to see if the run command for the appllication has been inserted into the registry. If it has, the the TCheckBox is checked, otherwise it is not.

Tuesday 21 June 2011

Tip: Opening a file with a non-default application - Part II

Looking back at my last post, I just realised that the Mac version might not work properly. The shell path of a folder item in RealBasic is an 'escaped string'. This means that a file path such as /Users/markoxley/Desktop/Untitled Folder would end up as /Users/markoxley/Desktop/Untitled\ Folder (note the back slash before the space in 'Untitled Folder').

To fix this, we can implement a very simple function:

 

Sub UnEscape(value As String) As String

 Dim s As String

  Dim index as integer=0

  while index<Len(value)

    index=index+1

    if mid(value,index,1)="\" then

      if index<>Len(value) then 

        index=index+1

        s=s+mid(value,index,1)

      end if

    else

      s=s+mid(value,index,1)

    end if

  wend 

  Return s

End Sub

We would then replace the original subroutine with this:

 

Sub OpenFileWith(DocumentPath As FolderItem, ApplicationPath As FolderItem)

  Dim ShellString As String

  Dim sh As Shell=New Shell

  #if TargetMacOS

    ShellString="open -a '" + UnEscape(ApplicationPath.ShellPath) + "' '" + UnEscape(DocumentPath.ShellPath) + "'"

  #elseif TargetWin32

    ShellString=ApplicationPath.AbsolutePath + " " + DocumentPath.AbsolutePath

  #endif

  

  sh.Execute(ShellString)

End Sub

Sunday 5 June 2011

Tip: Opening a file with a non-default application

I have worked on a couple of projects which have required me to designate an application to open a file and in some circumstances, this is not the default application. Therefore, I came up with a small routine in RealBasic to do this (only Mac and Windows I'm afraid)

 

Sub OpenFileWith(DocumentPath As FolderItem, ApplicationPath As FolderItem)

  Dim ShellString As String

  Dim sh As Shell=New Shell

  #if TargetMacOS

    ShellString="open -a '" + ApplicationPath.ShellPath + "' '" + DocumentPath.ShellPath + "'"

  #elseif TargetWin32

    ShellString=ApplicationPath.AbsolutePath + " " + DocumentPath.AbsolutePath

  #endif

  

  sh.Execute(ShellString)

End Sub

 

On a Mac, it also appears that you can open the application by just using its name, so this can also be addressed by the overriding the subroutine with the following:

 

Sub OpenFileWith(DocumentPath As FolderItem, ApplicationName As String)

  #if TargetMacOS

    Dim ShellString As String

    Dim sh As Shell=New Shell

    ShellString="open -a '" + ApplicationName + "' '" + DocumentPath.ShellPath + "'"

    sh.Execute(ShellString)

  #endif

End Sub

 

Hope this helps anyone else who needs to do something like this.

Friday 28 January 2011

New direction

Well, it has finally happened. I have succumbed to the lure of the mobile market. I spent the last week teaching myself to program games for Android devices.

It turned out to be easier than I was expecting. Apart from getting my head around the Activity lifecycle, I thought it was quite straight forward.

This does not mean that I will be abandoning desktop platforms, I am hoping to produce desktop and mobile versions of future projects. I will also be looking at applications that will use both desktop and mobile devices in tandem, but more of that at another time.

As I am talking about mobile devices (actually, I'm typing this on my tablet), I have begun to use Evernote to store code snippets. This service, available at http://www.evernote.com, is a marvellous way to synchronise data between devices. I whole heartedly recommend checking it out.

Published with Blogger-droid v1.6.6

Tuesday 18 January 2011

Back to work

Christmas is finally over and after a slightly extended break from coding, I am back at it.
I am revisiting an old project that I abandoned last year, Senet Collection. This time, I am using my framework, which is allowing me to concentrate more on the game, rather than the mechanics, although I have found a bug in the framework that causes labels to shift when a dialog is displayed over the top. Not sure what is causing this, but until I can find the problem, I have created a work around solution.
"What is Senet?" I hear you cry.
It is thought to be the forerunner of backgammon, as played by the ancient Egyptians. Unfortunately, the actual rules of the game have been lost in the mists of time, however, several people have attempted to work them out. In light of this, I have decided to create my computerised version with four sets of rules, as created by Gustave Jéquier, Timothy Kendall, R. C. Bell and Professor John Tait. There are other variations, but I will be sticking to the four mentioned.
Here are a couple of screen shots to wet your appetite.