Page 1 of 1

Building An Application - POS/Cash Register - Part Two The Display

#1 tlhIn`toq  Icon User is online

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5431
  • View blog
  • Posts: 11,642
  • Joined: 02-June 10

Posted 07 June 2010 - 11:05 AM

*
POPULAR

This is the continuation of
Building a C# application - Cash register - Part 1
In part 1 we built a virtual 10-key keyboard. While doing so we learned a few things about planning ahead, inheritance and events.

Our virtual RegisterKeypad (which inherited from the more generic GenericKeypad class) had one purpose in life: To raise events in response to user actions.

Here in part two we are going to make a GenericDisplay class, then inherit from it to make a more specific RegisterDisplay control. It too will have only one purpose in life: To display values - but to do so in a formatted in interesting way for use on our cash register.

We aren't going to get into deeper topics of how to graphically draw cool LED looking displays etc. We are going to use fonts and labels so we can keep on topic. There is nothing stopping you from finding some nice LED font to use, if that is a look you like.

Let's stop for a moment and THINK before we code. Radical for some. We could quickly through together some label in a box and call it done - then every time we use it our main program has to do all the tedious work of formatting the text: Or we could decide to spend a little extra time building this control so it handles all the boring tasks on it's own, and our main program only has to send it a value. Hmmmm... Work smarter, not harder. Make our code and controls re-usable. Iron out all the bugs in the small bit of code that makes up the control and know it is *DONE* so we don't have to re-create it over and over and over and over and over. ?? Which way should we go?

In part one we made a Display project. It has a UserControl1.cs user control. We need to rename that to GenericDisplay just like we did with the GenericKeypad in the Keypad project.

Let's give it some methods that seem reasonable for all kinds of currency displays we would want to use in our cash register. What kinds of things would we need to do *to* a display, and what kinds of things would we need to get *from* a display? It's value for one. There are really two kinds of values that a display might have: Numeric and string. A cash register might display "10.24", but it could also display the item like "Nails, box" and when the transaction is done, it might say "Thank you for shopping here" - and when logged out it might read "register closed". So we should be able to send it either a numeric or string value, as well a get from it a bool telling us whether or not the current display is a numeric value just so our main program doesn't have to decide each and every time. Right now your code should still look like this
namespace Display.cs
{
    public partial class GenericDisplay : UserControl
    {
        public GenericDisplay()
        {
            InitializeComponent();
        }
    }
}

We're going to need to methods for setting the text on the display. One for when a string is wanted, the other for when a number is wanted.
        public virtual void SetDisplay(string TheText)
        {
            //TODO: Set the display to the passed in string value
        }
        public virtual void SetDisplay(decimal TheAmount)
        {
            //TODO: Format, then display the passed in numeric value
        }



Let's break down the signature of one of these methods.
public virtual void SetDisplay(string TheText)
public - This means all other classes can see this method
virtual - This means that inherited classes can make a new method using this name to replace it's purpose. We'll see the use and power of this later.
void - This method does not return any result
SetDisplay - The name of this method
(string TheText) - The arguments being passed into this method when called. We expect to receive a string and we will refer to it as TheText.

The two comments have special meanings to Visual Studio. //TODO: is a special comment that Visual Studio looks for to maintain a ToDo list for you so you don't forget what you need to finish.
Attached Image

Notice the TaskList is already populated with these two comments, including the name of the file they are in and even the line numbers. When viewing the Task List all you have to do is double-click one of these lines to be whisked away to that comment. Not bad huh? Magical bookmarks within code so you can stub out your thinking with methods while working out the logic flow. Then come back and fill in the meat of the method later.

Here's how these two methods are going to work. If the programmer sends a string to the Display class then it means he knows just what he wants it to display so we will trust it. If he sends a number, then we wants it formatted to match the property currency expectations.

Windows already has preferences in the operating system for globalization and setting the way the user wants numbers to be formatted and displayed.
Attached Image
Attached Image

Since I'm lazy and don't want to re-invent the wheel, I'm just going to ask the .NET framework to do the work for me.

I'm not going to go deep into the syntax of the C# language here. The MSDN and about 500 books do that just fine. But briefly we are using the built-in formating feature to pass argument use TheAmount as argument 0, and 'C' as the format we want which is currency. Windows will then look up the currency settings and apply all the rules for us turning 1000000.0256 into "$ 1,000,000.03" if you are using English/United States.

While we are here let's discus a couple other things. Did you notice that we have two methods with identical names? We have SetDisplay that takes an argument of a string, and we have SetDisplay that takes an argument of a decimal, but otherwise they are the same. This is call "overloading" and is completely legal, and even desirable when used in certain circumstances, like this one, where the functions have nearly identical use. Notice how Intellisense was kind enough to give us a popup menu showing us both of our overloaded methods along with their argument types? My favorite example of this is the MessageBox.Show()
Attached Image
There are a LOT of overrides, giving you the capability of sending just one string, two strings, strings plus picking the buttons, string plus picking the buttons and the icon... specifying the parent window as the owner of this messagebox and so on and so on.

We are doing the same here, but on a smaller scale. We are giving future coders that use our GenericDisplay control and it's inheritance-derived offspring, two ways of setting what will be shown on this display. Guess what? We have just completed the TODO for code line 24. The decimal form of this overloaded method now knows what to do. We can delete line 24 because that task is done. In doing so you will see it disappear from our Task List.

It is now time to derive a simple inherited control from our GenericDisplay. Right-click on the Display.cs project. Choose "Add". Choose UserControl. Name the new UserControl "SimpleDisplay" You should now have a simple grey UserControl. Right-click anywhere on the grey and choose "View Code". Instead of this deriving from .NET's UserControl class we want it to derive from our class, so change line 11 to look like this
public partial class SimpleDisplay : GenericDisplay
Go back to the designer, make the gray area bigger so you have some room to work, drag a text box on to the gray area. Now in the Properties pallet change the dock to fill
Attached Image
and the 'multiline' to true. You now have a simple display that uses a self-resizing textbox - that inherits our SetDisplay methods from GenericDisplay.

Like my first girlfriend, looks but no brains. Let's give this control a method so it will now how to do something. The GenericDisplay had a virtual method of SetDisplay(string TheText) that we never got around to giving any code. That was because the generic display had no way to show it. But this SimpleDisplay does: It has a textbox. So we are going to override this method from the base class, and do something with it here.
        public override void SetDisplay(string TheText)
        {
            textBox1.Text = TheText;
        }



From the debug menu choose "Start Debugging" or press the F5 key. Your Form1 will run and not be any different than before. Close the form. Just like the keypad control, this was just to compile the code and have the Visual Studio toolbox add these two Display controls.
Attached Image

Let's put it to use in our Form1 testing area. Drag a new SimpleDisplay to the form. I dropped mine just above our earlier textbox and made it equally wide.
Attached Image
Go to the code for Form1. Right now we react to the KeyPad events like this
        private void registerKeypad1_ButtonPressed(object sender, KeyPressEventArgs e)
        {
            textBox1.Text += e.KeyChar;
        }

By adding one line, our new SimpleDisplay will also get updated
        private void registerKeypad1_ButtonPressed(object sender, KeyPressEventArgs e)
        {
            textBox1.Text += e.KeyChar;
            [B][I]simpleDisplay1.SetDisplay(textBox1.Text);[/I][/B]
        }

F5 Start Debugging this now. Click some numbers. You should have both boxes update to the same text. Not really exciting, huh? Lets try using that other SetDisplay method: The one that takes a number and automatically formats the text to match the system currency preferences.
private void registerKeypad1_ButtonPressed(object sender, KeyPressEventArgs e)
{
    textBox1.Text += e.KeyChar;
    //simpleDisplay1.SetDisplay(textBox1.Text);
   [I][B] simpleDisplay1.SetDisplay(Convert.ToDecimal(textBox1.Text));[/B][/I]
}

Notice we commented our earlier call, and added this new call that will take the text we have, convert it to a decimal, and use it as the argument for SetDisplay. Visual Studio will route it to SetDisplay(decimal TheAmount) instead of SetDisplay(string TheText) because we are sending a decimal. It does the routing work for us based on the signature of the call.

F5 Start Debugging again. Click on a few numbers. Wow! Look at that. The textbox still shows text, but the SimpleDisplay receives the number, formats the value to a currency string, and shows that instead
Attached Image
Our main application didn't have to do the work: The SimpleDisplay control did. And if your user changes preferences in the operating system with respect to how currency should be displayed, you have NO WORK to do in this control. Niiiiiiiiiiiiiiiiice.

But this doesn't look very techy or digital or like what we expect to see from a cash register readout. What if we change the font to a nice LCD or Display screen font.
Attached Image

Getting closer... but still not quite there. What we want would look more like this:
Attached Image
So how do we do that? By using a couple more overrides, but this time the base methods come from the UserControl class. In our SimpleDialog we override the forecolor and backcolor properties and pass them to the textbox we are using.
public override System.Drawing.Color ForeColor
{
    get
    {
        return textBox1.ForeColor;
    }
    set
    {
        textBox1.ForeColor = value;
    }
}

public override Color BackColor
{
    get
    {
        return textBox1.BackColor;
    }
    set
    {
        textBox1.BackColor = value;
    }
}

Now when you set the backcolor of the control, it will make that the backcolor of TextBox1. Same with the forecolor. Set the backcolor to black and the forecolor to Lawn green.

There is also one really big cheat that we don't do for final projects, but for now makes it look cleaner JUST FOR TESTING. I dragged the SimpleDisplay on top of the textbox from part 1, covering it up completely. Its still there and we are still using it. We just can't see it. Bad bad bad in release versions. But fast and dirty while testing just to check out our affect.

Between part 1 and part 2 we've done a lot of code changes, so I'm going to wrap this up with the code for each file, just so we are all on the same page. Notice how little code there really is. 20-80 lines for any individual piece.

GenericDisplay
namespace Display.cs
{
    public partial class GenericDisplay : UserControl
    {
        public GenericDisplay()
        {
            InitializeComponent();
        }

        public virtual void SetDisplay(string TheText)
        {
            //TODO: Set the display to the passed in string value
        }
        public virtual void SetDisplay(decimal TheAmount)
        {
            string temp = string.Format("{0:C}", TheAmount);
            SetDisplay(temp);
        }
    }
}




SimpleDisplay
namespace Display.cs
{
    public partial class SimpleDisplay : GenericDisplay
    {
        public SimpleDisplay()
        {
            InitializeComponent();
        }

        public override void SetDisplay(string TheText)
        {
            textBox1.Text = TheText;
        }

        public override System.Drawing.Color ForeColor
        {
            get
            {
                return textBox1.ForeColor;
            }
            set
            {
                textBox1.ForeColor = value;
            }
        }

        public override Color BackColor
        {
            get
            {
                return textBox1.BackColor;
            }
            set
            {
                textBox1.BackColor = value;
            }
        }
    }
}




Form1 used for testing
namespace DemoPOS
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void registerKeypad1_ButtonPressed(object sender, KeyPressEventArgs e)
        {
            textBox1.Text += e.KeyChar;
            //simpleDisplay1.SetDisplay(textBox1.Text);
            simpleDisplay1.SetDisplay(Convert.ToDecimal(textBox1.Text));
        }
    }
}




GenericKeypad
namespace Keypad.cs
{
    public partial class GenericKeypad : UserControl
    {
        public GenericKeypad()
        {
            InitializeComponent();
        }


        #region Events
        public event KeyPressEventHandler ButtonPressed;
        #endregion Events

        #region Methods
        public void RaiseButtonPressed(char WhatToSend)
        {
            KeyPressEventHandler handler = ButtonPressed;
            if (handler != null)
            {
                handler(this, new KeyPressEventArgs(WhatToSend));
            }
        }
        #endregion Methods

    }
}




RegisterKeypad
namespace Keypad.cs
{
    public partial class RegisterKeypad : GenericKeypad
    {
        public RegisterKeypad()
        {
            InitializeComponent();
        }

        private void btn1_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('1');
        }

        private void btn2_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('2');
        }

        private void btn3_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('3');
        }

        private void btn4_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('4');
        }

        private void btn5_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('5');
        }

        private void btn6_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('6');
        }

        private void btn7_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('7');
        }

        private void btn8_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('8');
        }

        private void btn9_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('9');
        }

        private void btn0_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('0');
        }

        private void btn00_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('0');
            RaiseButtonPressed('0');

        }

        private void btnEnter_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('E');
        }

        private void btnPlus_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('+');
        }

        private void btnMinus_Click(object sender, EventArgs e)
        {
            RaiseButtonPressed('-');
        }
    }
}



Part 0 - Custom events
Part 1 - Virtual Keypad (inheritance)
Part 2 - The LCD display panel
Part 3 - [coming soon]
Part 4 - [after that]

This post has been edited by tlhIn'toq: 07 June 2010 - 11:50 AM


Is This A Good Question/Topic? 16
  • +

Replies To: Building An Application - POS/Cash Register - Part Two

#2 tlhIn`toq  Icon User is online

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5431
  • View blog
  • Posts: 11,642
  • Joined: 02-June 10

Posted 20 February 2011 - 07:37 PM

View PostElJagg, on 20 February 2011 - 08:22 PM, said:

View PosttlhIn`toq, on 26 January 2011 - 02:25 PM, said:

View PostTheomi, on 10 November 2010 - 06:01 PM, said:

Nice tut now im waiting for the rest :P

I'm waiting for some free time. And some inspiration on a next topic.

I think you shud do the complete tutorial and sell it ( I would buy it if it is reasonable.)


That's actually where the rub kinda come in. I've recently been hired to write a proper and complete POS system. Which means I really have to be careful about posting code on how to make a POS system. I don't need legal issues or claims that I made paid, proprietary code freely available to the public.

I'm going to have to re-think a my concept of a series of tutorials. I would like them to have a running theme, but one that doesn't necessarily translate to a project that someone is either going to try to publish for pay and pass off as their own work. Or one that could actually become a paying contract for me.

Maybe I just can't do them as a running theme.... I don't know.

If you or anyone else can think of an idea that matches the criteria above for an imaginary software that I could build a series of tutorial around please PM them to me (rather than dirty up this thread).

Or just some one-off topics that you feel aren't already covered.
Was This Post Helpful? 0
  • +
  • -

#3 madmorgan  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 104
  • Joined: 07-May 10

Posted 19 December 2012 - 10:23 AM

When is this post going to be updated with part 3
Was This Post Helpful? 0
  • +
  • -

#4 tlhIn`toq  Icon User is online

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5431
  • View blog
  • Posts: 11,642
  • Joined: 02-June 10

Posted 19 December 2012 - 10:29 AM

Only one person has ever asked for more on this and they were very clear they wanted to just copy/paste the code into a product so they could sell it.

If someone let's me know what areas they want to learn/work-on next as part of their development I'll build more tutorials. I try to be 'customer driven' even in free tutorials. There is no point putting out tutorials on things that nobody cares about: It just wastes time.

So what would you like to see as part of a next/new tutorial?
Was This Post Helpful? 0
  • +
  • -

#5 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8893
  • View blog
  • Posts: 33,351
  • Joined: 12-June 08

Posted 19 December 2012 - 10:39 AM

Quote

So what would you like to see as part of a next/new tutorial?

The part where I profit off it? ;)
Was This Post Helpful? 1
  • +
  • -

#6 madmorgan  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 104
  • Joined: 07-May 10

Posted 19 December 2012 - 10:41 AM

I would like some information on processing payments and printing a bill at the end of the tranication
Was This Post Helpful? 0
  • +
  • -

#7 tlhIn`toq  Icon User is online

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5431
  • View blog
  • Posts: 11,642
  • Joined: 02-June 10

Posted 19 December 2012 - 11:02 AM

Processing credit cards is going to depend on your merchant services provider. They each have their own API for developers. For example:
Intuit GoPayment API
PayPal API

As for printing... Wow, there are SO MANY tutorials on how to print that building another just seems redundant.
Printing in C# -Here on D.I.C.
Printing an invoice
Another printing in C# tutorial

This post has been edited by tlhIn`toq: 19 December 2012 - 11:03 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1