c# project report - storage.googleapis.com · merit of straightforward user interface and user...
TRANSCRIPT
1
COMP 2210 Visual Programming
Project Report
Project Title: Automated Ordering
System at Restaurants
Team #7
Members: Anton Bukreev
Tiasa Mondol
2
Point Of Sale Software
Point of sale software helps small business automate their routine processes and minimize the waiting
time for the customer. Therefore, this kind of software should be as simple and intuitive as possible.
Since most of small businesses already own a desktop computer, they can use it as a front-desk to take
orders. The software on today’s market is overwhelmingly expensive and unnecessarily complicated.
Personnel usually needs training to accommodate to this kind of software. That’s why we decided to
make a POS software that is super-easy to use, easy to install and useful to any small business.
Basic features:
● Can be installed to any windows-based machine
● Also works on Windows RT tablets
● Is totally free
● Can run even on the oldest computers
● Simple!
This Point of Sale software is written in C#, using only standard class library, that means it can run on
both x64 and x32 systems, Intel- or ARM-based versions of windows, as long as it supports .NET
Framework.
Developing stages
At first, the purpose of the whole project was proposed: to make a simple and easy to use POS software
that wouldn’t require any personnel training since it would be intuitive. It should work on both
keyboard\mouse devices and touch screens, so all the controls were designed with touch screen in
mind: minimum size of the user interface should not be less than 10mm on the screen and the space
between elements should not be less than 5mm. Having that in mind, the team began to research on
existing POS software and User Interfaces it have. Team soon figured out that all of existing software,
available for small business is too complicated and not easy to set up at all. Our software had to
resemble key User Interface elements of existing software to help people, who already had used POS
software before, adapt to our software with less effort.
We then created the simplest User Interface anyone can imagine – several big buttons with clear bold
captions and straightforward controls. We included some additional buttons, that aren’t usually a part
of POS UI, but are convenient to have at hand: for example, we added a “delete last” control, that just
removes the item last added to the order. Remembering touch controls, we’ve made a numeric input
panel, that is used through all the application to enter numbers from touch screen.
Database was designed to solve several problems at once: to store the information for the POS Software
and to provide a usable and convenient back-end, where administrator could add information about
items and generate financial reports, based on sales made through the application. We have chosen
3
Microsoft Access database because it is a format that is publicly available through Microsoft Office suite,
that is probably installed on most Windows machines. Other database engines like MySQL maybe
provide more features, but are hard to maintain for non-trained personnel and are unnecessarily
complicated for the small application of this kind.
Designing database was essential step in application planning before implementing features in code
since it describes most of the data structures used in the application. Once we finished the database
design stage, we start to create data structures for the app. Since it is an application of rather small
scale, only two simple structures were used: one for an item in stock that represents a dish or a service
in menu, and one for a sale event that makes discount to the whole order. Both data structures are
stored in a separate class that contains just the prototypes of those classes.
Next, we began to implement logic behind the user interface. We’ve created panels that are accessed
just like dialogue boxes and can return a value after they are closed. We’ve created a custom button
class that contains an ID of an item it represents. Space on the screen is quite limited when you think of
touch screens with all their big touch-oriented controls, so we figured out a way to navigate through
virtually unlimited number of items with just buttons. We used a layout of a square 5x3 elements, which
are separated to pages. User can move back and forth through the pages and select needed item. Even
if the item is lots of clicks away – user can always use a barcode button and manually enter the ID of
needed item or service and it could possibly save some time for the customer.
Class structure
There are three forms in the application: one main form called POSForm, one form for the digital input,
called NumericInputDialog and third, representing a sale deal picker panel, named SaleFormDialog. Their
source code is available in the Listing section of this document.
There is a class, responsible for all the database management – DBAdapter. It is used as an interface to
database and it provides simple to use methods for getting items for a specified order or getting
information about the sale, based on it’s ID. This allows us to separate the interface and the
implementation of database transactions. In real words, if we ever decide to change the database model
– all we have to do is to change few methods in this class without refactoring the whole application.
Handy!
There is a class called DataTypes, that is just a prototype container for two classes – Good and Sale.
Those are the data structures that have their own parameters and used independently. If any new data
types will be created – they would be stored in this class. It allows us to store small pieces of code in one
place and easily create Lists of objects of the same type.
Class ButtonWithId is a custom button control that is just a regular button, but with a pointer to an
integer ID. It is used to dynamically add lots of buttons that represent items or sale events to the form.
When user clicks one – it is vital to know what item ID was selected. That is why we store ID within a
button.
4
Database design Database of this application consists of three main tables: Items, Orders and OrderItems.
Items table contains data about items or services for sale and the main form is filled with the buttons,
generated from this information. It includes name, price, relative URL to a picture of this item, and of
course, ID.
Orders table contains data about orders: one order is comprised of multiple items and possibly has a
discount applied. This table stores the final price for the order and the tax applied to it. Yes, the total can
be calculated dynamically based on the prices of the items in the order, but this data redundancy is
needed in case the item price changes. Since we store the total order amount in a separate field – we
still will be able to create valid financial reports based on order total.
OrderItems table contains the ‘links’ from the order to items. In this way, you can easily ask the DB
about all the items from order number X and get their detailed information. It is comprised of just two
fields: OrderID and ItemID.
We did not implement any predefined financial reports since it can confuse the end user. Most of the
companies require different format of reports anyways, and since Access is giving all the tools to create
the needed report in defined format – we are leaving report generation to the end user or
administrator.
Difficulties faced
None of us was aware that Microsoft Access does not implement full SQL stack. For example, it does not
support the LIMIT keyword, which is quite essential when you do pagination. The workaround is quite a
peculiar thing itself: we use two nested queries, asking DB to get last 12 results which are not in the
second query. Here is an example, where we are skipping 24 records from the beginning and getting
next 12 records:
SELECT TOP 12 * FROM Items WHERE ID NOT IN (SELECT TOP 24 ID FROM Items)
Another difficulty was to implement a panel for getting a user input – a digital input with touch-enabled
controls or just a panel to select a sale from a list. The difficulty here was to create a custom response
from dialog box. We mitigated this difficulty by passing the reference to a parent in a newly created
form and making the new form call itself as a dialog of referenced parent. In this way, the flexibility was
achieved: this dialogue window could be called with a single line of code from any form, not just exact
selected one. The source code of the implementation of this concept can be found in Listing section.
5
Testing We’ve tested our application on male and female gorillas – both demonstrated full confidence with POS
software after control time of 10 minutes. We believe, it is a decent result that can be considered a
merit of straightforward User Interface and user friendly controls. However, one of gorillas apparently
didn’t like the Windows RT tablet and ate it during the test, so it’s results couldn’t be acquired.
Shortcomings and future work Of course, every application have its shortcomings at the early development stages. This Point of Sale
application is no exception. Here is the list of several shortcomings and the proposed ways to mitigate
them:
● Only one discount can be active at a time
Just need to make the smart discount storage and calculation. This is a rather simple thing to do
so it can be a decent candidate for the next version.
● Needs MS Access to run and maintain
Let’s face it: not everybody has paid for Office suite. There are free DB engines out there – not
so user-friendly and not so simple, but we need to give user a choice. The application could have
a universal connection selector setting – with Microsoft Access as default for the sake of
simplicity.
● Images are served from local storage on HDD.
There are several possible scenarios to mitigate this shortcoming: first, the application could use
a remote web-server with images, This makes more sense in case of a remote DB provider, so all
the data and images could be stored in the cloud and just cached locally. Second way of solving
it: images should be served in a packed format and unpacked only during execution. However,
this requires a mechanism of controlling the resource versions, which is not user-friendly.
● The application has too few settings.
This is actually not a bad thing, taking the ease of use in account. But some basic settings would
be essential – like where is DB file, what type of DB it is, how much is the tax, etc.
This list is a short overview of non-essential shortcomings that are quite easy to mitigate. This list can be
used as a plan for future work on this software and demonstrates some futures from possible future
versions.
Used resources
MSDN Library – http://msdn.microsoft.com/library
6
C# For Dummies – Bill Sempf, Chuck Sphar, Stephen Randy Davis. 2010, Wiley Publishing ©
Stack Overflow – http://stackoverflow.com
Slides by Mridula Sharma – http://mridulasharma.com
Screenshots
The Interface :
7
Barcode Scanner :
8
Sale Selection:
Database Update :
Class listings
POSForm.cs
/*************************************************************** * C# Project : Automated Ordering System : Point of Sale * Team #7
9
* Members: Anton Bukreev , Tiasa Mondol */
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO; using System.Collections;
namespace WindowsFormsApplication4 { public partial class POSForm : Form { private DBAdaptor db; // Listt with ordered items private List<DataTypes.Good> currentOrder; private int currentSale = 0; private int currentOffset = 0; private int currentBevOffset = 0; public int orderno=0; public POSForm() {
InitializeComponent(); // Beverage previous next button not shown at first
button4.Enabled = false; button4.Visible = false; button5.Enabled = false; button5.Visible = false; button6.Enabled = false; button6.Visible = false; db = new DBAdaptor(); drawGoods(); currentOrder = new List<DataTypes.Good>(); }
// Populating the form with item button from data base public void addGoodButton(int id, string imageURL, string name) { ButtonWithId btn = new ButtonWithId(); if (imageURL == "" || !File.Exists(imageURL)) imageURL = @"C:\Users\Toxuin\Documents\IMAGES\noItemImage.png"; btn.Image = Image.FromFile(imageURL);;
10
btn.ImageAlign = System.Drawing.ContentAlignment.BottomCenter; btn.Width = 120; btn.Height = 120; btn.ItemId = id; btn.Text = name; btn.TextAlign = System.Drawing.ContentAlignment.TopCenter; btn.Click += (sender, evnt) => { itemClickCallback(((ButtonWithId)sender).ItemId); };
// Setting the buttom number limit Point lctn = goodsBox.DisplayRectangle.Location; int initY = lctn.Y; int initX = 30; int row = (int)(goodsBox.Controls.Count / 5); int col = goodsBox.Controls.Count - (row * 5); lctn.Y = initY + row * 130; lctn.X = initX + col * 130; btn.Location = lctn;
goodsBox.Controls.Add(btn); }
// Drawing fast foods private void drawGoods() { button2.Enabled = true; button3.Enabled = true; if (currentOffset == 0) button2.Enabled = false; goodsBox.Controls.Clear();
List<DataTypes.Good> itemsList = db.getGoods(currentOffset, 20);
foreach (DataTypes.Good goodey in itemsList) { addGoodButton(goodey.id, goodey.imageURL, goodey.name); } if (itemsList.Count < 20) button3.Enabled = false; }
private void button3_Click_1(object sender, EventArgs e) { currentOffset = currentOffset + 20; drawGoods(); }
private void button2_Click_1(object sender, EventArgs e) { currentOffset = currentOffset - 20;
11
if (currentOffset < 0) currentOffset = 0; drawGoods(); }
// Drawing Beverage private void drawBeverage() { button4.Enabled = true; button5.Enabled = true; if (currentBevOffset == 0) button4.Enabled = false; goodsBox.Controls.Clear();
List<DataTypes.Good> itemsList = db.getBeverage(currentBevOffset, 20);
foreach (DataTypes.Good goodey in itemsList) { addGoodButton(goodey.id, goodey.imageURL, goodey.name); } if (itemsList.Count < 20) button5.Enabled = false; }
// SALE PANEL private void btnSale_Click(object sender, EventArgs e) { SalesFormDialog sfd = new SalesFormDialog(this); if (sfd.getSaleValue() <= 0) { // CANCELLED MessageBox.Show("No Sale Selected"); return; } else if (sfd.getSaleValue() > 100) { // CHECK FOR > 100 - MEANS DB CRAZEH MessageBox.Show("DB ERROR"); return; }
currentSale = sfd.getSaleValue(); MessageBox.Show("Sale Value updated to "+currentSale+"%"); recalculateTotal(); }
private void goodManualBtn_Click(object sender, EventArgs e) { NumericInputDialog nid = new NumericInputDialog(this); DataTypes.Good goodey = db.getItemById((int)nid.getResult()); if (goodey != null)
12
{ // DO MAGIC HERE AS WELL MessageBox.Show(goodey.name); itemClickCallback(goodey.id); } else MessageBox.Show("Item not found!"); }
private void button1_Click(object sender, EventArgs e) { button2.Enabled = false; button2.Visible = false; button3.Enabled = false; button3.Visible = false; button4.Visible = true; button5.Visible = true; button6.Visible = true; button6.Enabled = true; currentBevOffset = 0; drawBeverage(); }
private void itemClickCallback(int id) { // THIS FUNCTION IS CALLED WHENEVER USER CLICKS THE ITEM BUTTON DataTypes.Good item = db.getItemById(id); currentOrder.Add(item); recieptListBox.Items.Add(item.name + " " + item.price); recalculateTotal();
}
private void recalculateTotal() { double total = 0; foreach (DataTypes.Good thingy in currentOrder) { total += thingy.price; } if (currentSale != 0) total = total - (total / 100 * currentSale); printButton.Text = "Total: " + total; }
private void printButton_Click(object sender, EventArgs e) { // SAVE CURRENT ORDER TO DB orderno++; db.saveOrder(currentOrder, currentSale , orderno); currentOrder = new List<DataTypes.Good>(); currentSale = 0; printButton.Text = "Total: " + 0;
13
recieptListBox.Items.Clear(); MessageBox.Show("Order was succesfully updated to Database"); }
private void btnDelLast_Click(object sender, EventArgs e) { if (currentOrder.Count == 0) return; currentOrder.RemoveAt((currentOrder.Count) - 1); // RECALCULATE SALE ITEM POSITION IN RECIEPT!!! redrawReciept(); }
// Updates the receipt box private void redrawReciept() { recieptListBox.Items.Clear(); foreach (DataTypes.Good thingy in currentOrder) { recieptListBox.Items.Add(thingy.name + " " + thingy.price); }
recalculateTotal(); }
private void button4_Click(object sender, EventArgs e) { currentBevOffset = currentBevOffset - 20; if (currentBevOffset < 0) currentBevOffset = 0; drawBeverage(); }
private void button5_Click(object sender, EventArgs e) { currentBevOffset = currentBevOffset + 20; drawBeverage(); }
private void button6_Click(object sender, EventArgs e) { button1.Visible = true; button1.Enabled = true; button4.Enabled = false; button4.Visible = false; button5.Enabled = false; button5.Visible = false; button2.Visible = true; button3.Visible = true;
14
button6.Visible = false; button6.Enabled = false; currentOffset = 0; drawGoods(); }
} }
DataTypes.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
// making two data types of good and sale namespace WindowsFormsApplication4 { class DataTypes {
public class Good { public int id; public string name; public string imageURL; public double price; }
public class Sale { public int id; public string name; public int value; }
} }
ButtonWithId.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms;
15
// Separately Created Button class that serve our purpose namespace WindowsFormsApplication4 { public class ButtonWithId : Button { public int id; public int ItemId { get { return id; } set { id = value; } } } }
DBAdaptor.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data.OleDb; using System.Data.SqlClient;
namespace WindowsFormsApplication4 { class DBAdaptor {
private OleDbConnection connection = null; private bool ready = false;
public DBAdaptor() { if (connection == null) reopenConnection(); connection.ConnectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;" + @"Data Source= G:\Project\AwesomePOS-master\AwesomePOS.accdb;Persist Security Info=False;"; try { connection.Open(); ready = true; } catch (Exception ex) { Console.WriteLine("Failed to connect to data source!!! " + ex); } }
private void reopenConnection() { if (connection != null) closeConnection(); connection = new System.Data.OleDb.OleDbConnection();
16
}
public void closeConnection() { connection.Close(); connection.Dispose(); ready = false; }
public DataTypes.Good getItemById(int itemId) { DataTypes.Good goodey = new DataTypes.Good(); string sqlStr = @"SELECT * FROM Items WHERE ID = " + itemId; OleDbCommand cmd = new OleDbCommand(sqlStr, connection); OleDbDataReader reader = cmd.ExecuteReader(); if (reader.Read()) { goodey.id = Convert.ToInt32(reader["ID"].ToString()); goodey.imageURL = reader["ImageURL"].ToString(); goodey.name = reader["ProductName"].ToString(); goodey.price = Convert.ToDouble(reader["Price"].ToString()); } else return null; return goodey; }
public List<int> getItemsForOrderId(int orderId) { List<int> list = new List<int>(); OleDbCommand cmd = new OleDbCommand("SELECT ProductId FROM OrderItems WHERE OrderId = " + orderId, connection); OleDbDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { list.Add(Convert.ToInt32(reader["ProductId"].ToString())); } return list; }
// Get sales with appropitae excape numbers public List<DataTypes.Sale> getSales(int skip = 0, int count = 0) { List<DataTypes.Sale> list = new List<DataTypes.Sale>();
string sqlString = @"SELECT * FROM Sales "; if (skip != 0 || count != 0) sqlString += @"WHERE ID BETWEEN " + (skip+1) + " AND " + (skip+count) + " AND ACTIVE = YES"; else sqlString += @" WHERE ACTIVE = YES"; OleDbCommand cmd = new OleDbCommand(sqlString, connection); OleDbDataReader reader = cmd.ExecuteReader();
17
while (reader.Read()) { DataTypes.Sale sale = new DataTypes.Sale(); sale.id = Convert.ToInt32(reader["ID"].ToString()); sale.name = reader["SaleName"].ToString(); sale.value = Convert.ToInt32(reader["SaleValue"].ToString()); list.Add(sale); } return list; }
public List<DataTypes.Good> getBeverage(int skip = 0, int count = 0) { List<DataTypes.Good> list = new List<DataTypes.Good>(); string sqlString; if (skip != 0) sqlString = @"SELECT TOP " + count + " * FROM Items WHERE ID NOT IN (SELECT TOP " + skip + " ID FROM Items WHERE Type=" + "\'" + "Beverage" + "\'" + ") AND Type=" + "\'" + "Beverage" + "\'"; else sqlString = @"SELECT TOP " + count + " * FROM Items WHERE Type=" + "\'" + "Beverage" + "\'"; OleDbCommand cmd = new OleDbCommand(sqlString, connection); OleDbDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { DataTypes.Good goodey = new DataTypes.Good(); goodey.id = Convert.ToInt32(reader["ID"].ToString()); goodey.name = reader["ProductName"].ToString(); goodey.imageURL = goodey.imageURL = "G:/Project/AwesomePOS-master/Images/icon_2/" + goodey.name.ToLower() + ".png";
goodey.price = Convert.ToDouble(reader["Price"].ToString()); list.Add(goodey); } return list; }
public List<DataTypes.Good> getGoods(int skip = 0, int count = 0) { List<DataTypes.Good> list = new List<DataTypes.Good>(); string sqlString ; if (skip != 0) sqlString = @"SELECT TOP " + count + " * FROM Items WHERE ID NOT IN (SELECT TOP " + skip + " ID FROM Items WHERE Type=" + "\'" + "Food" + "\'" + ") AND Type=" + "\'" + "Food" + "\'"; else sqlString = @"SELECT TOP " + count + " * FROM Items WHERE Type=" + "\'" + "Food" + "\'"; OleDbCommand cmd = new OleDbCommand(sqlString, connection); OleDbDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { DataTypes.Good goodey = new DataTypes.Good(); goodey.id = Convert.ToInt32(reader["ID"].ToString()); goodey.name = reader["ProductName"].ToString(); goodey.imageURL = @"G:\Project\AwesomePOS-
18
master\Images\icon_2\"+goodey.name.ToLower()+".png"; goodey.price = Convert.ToDouble(reader["Price"].ToString()); list.Add(goodey); } return list; } public DataTypes.Sale getSaleById(int saleId) { DataTypes.Sale sale = new DataTypes.Sale(); string sqlStr = @"SELECT * FROM Sales WHERE ID = " + saleId + " AND Active = YES"; OleDbCommand cmd = new OleDbCommand(sqlStr, connection); OleDbDataReader reader = cmd.ExecuteReader(); if (reader.Read()) { sale.id = Convert.ToInt32(reader["ID"].ToString()); sale.value = Convert.ToInt32(reader["SaleValue"].ToString()); sale.name = reader["SaleName"].ToString(); } else return null; return sale; }
public bool testConnection() { return ready; }
internal void saveOrder(List<DataTypes.Good> currentOrder, int saleValue, int orderno) { double total = 0; OleDbCommand cmd = connection.CreateCommand(); foreach (DataTypes.Good thingy in currentOrder) { total += thingy.price; cmd.CommandText = @"INSERT INTO OrderItems (OrderId, ProductId) VALUES ('"+ orderno + "','" + thingy.id + "')"; cmd.ExecuteNonQuery();
}
cmd.CommandText = @"INSERT INTO Orders (ID ,Total, Tax, SaleValue) VALUES ("+orderno+",'"+ total + "','" + (total*saleValue/100) + "','"+saleValue+"')"; cmd.ExecuteNonQuery(); } } }
19
SaleFormDialogue.cs: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms;
namespace WindowsFormsApplication4 { public partial class SalesFormDialog : Form { private string saleName = ""; private int saleValue = 0;
private int currentOffset = 0;
private DBAdaptor db;
public SalesFormDialog(IWin32Window owner) { InitializeComponent(); db = new DBAdaptor(); redrawSales();
if (this.ShowDialog(owner) == DialogResult.OK) { //calls itself } db.closeConnection(); this.Dispose(); }
private void redrawSales() { prevBtn.Enabled = true; nextBtn.Enabled = true; if (currentOffset == 0) prevBtn.Enabled = false; saleBox.Controls.Clear(); List<DataTypes.Sale> saleList = db.getSales(currentOffset, 12); foreach (DataTypes.Sale sale in saleList) { addSaleButton(sale.id, sale.name); } if (saleList.Count < 12) nextBtn.Enabled = false; }
20
public void addSaleButton(int id, string name) { ButtonWithId btn = new ButtonWithId(); btn.Width = 120; btn.Height = 50; btn.ItemId = id; btn.Text = name; btn.Click += (sender, evnt) => { saleClickCallback(((ButtonWithId)sender).ItemId); };
// COULD GO OFF THE SCREEN Point lctn = saleBox.DisplayRectangle.Location; int initY = lctn.Y; int initX = 20; int row = (int)(saleBox.Controls.Count / 3); int col = saleBox.Controls.Count - (row * 3); lctn.Y = initY + row * 60; lctn.X = initX + col * 130; btn.Location = lctn; saleBox.Controls.Add(btn); }
private void saleClickCallback(int id) { DataTypes.Sale sale = new DataTypes.Sale(); if (id != 0) sale = db.getSaleById(id); saleValue = sale.value; saleName = sale.name; this.Dispose(); }
private void saleManualBtn_Click(object sender, EventArgs e) { NumericInputDialog nid = new NumericInputDialog(this); saleValue = (int) nid.getResult(); saleName = "Custom sale"; this.Dispose(); }
public int getSaleValue() { return saleValue; }
public string getSaleName() { return saleName; }
private void nextBtn_Click(object sender, EventArgs e) { currentOffset = currentOffset + 12; redrawSales(); }
21
private void prevBtn_Click(object sender, EventArgs e) { currentOffset = currentOffset - 12; if (currentOffset < 0) currentOffset = 0; redrawSales(); } } }
NumericInputDialogue.cs: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; // Numeric input dialogue for bar code namespace WindowsFormsApplication4 { public partial class NumericInputDialog : Form { private double result = 0; public NumericInputDialog(IWin32Window owner) { InitializeComponent(); if (this.ShowDialog(owner) == DialogResult.OK) { result = Double.Parse(numTextBox.Text); } this.Dispose(); } public TextBox numText;
private void clearBtn_Click(object sender, EventArgs e) { numTextBox.Text = ""; }
private void numBtn_Click(object sender, EventArgs e) { if (numTextBox.Text.Length >= 8) return; Button pushedButton = (Button)sender; if (pushedButton.Text.Length == 2 && numTextBox.Text.Length >= 7) return; numTextBox.Text += pushedButton.Text; Console.Beep(); // NOT WORKEY ON x64 SYSTEM. }
private void backspaceBtn_Click(object sender, EventArgs e) { if (numTextBox.Text == "") return; numTextBox.Text = numTextBox.Text.Remove(numTextBox.Text.Length - 1, 1);
22
}
public double getResult() { return result; } } }