在我們開發(fā)一些項目的時候腕柜,一般需要一些外圍的設(shè)備進行數(shù)據(jù)處理,如ID/IC讀卡器獲取卡號嘹狞、激光條碼掃描槍、USB攝像頭誓竿、USB方式的小票據(jù)打印機(POS打印機)磅网、USB來電錄音盒、普通打印機等一系列附屬設(shè)備筷屡。借助這些設(shè)備涧偷,可以使我們的業(yè)務(wù)流程更嚴謹簸喂,輸入數(shù)據(jù)更方便,或者能夠一些特殊的數(shù)據(jù)等功能燎潮。本文主要介紹其中的ID讀卡器(IC讀卡器)快速讀取卡號喻鳄,以及實用激光條碼槍的條碼掃描錄入功能,后面的一些硬件設(shè)備的處理确封,后續(xù)文章在繼續(xù)介紹除呵。
1、設(shè)備介紹
前面介紹的設(shè)備隅肥,在很多場合上都可能用到竿奏,如我的會員管理系統(tǒng)里面,就需要用到下面的設(shè)備處理腥放。
本文主要針對性了解ID讀卡器和條碼槍的設(shè)備數(shù)據(jù)處理泛啸,這兩種設(shè)備雖然不同,但是它們相似的地方就是都支持在光標處錄入數(shù)據(jù)的秃症,就有點類似我們的鍵盤快速錄入一樣候址,當(dāng)然激光條碼槍也支持很多種方式的事件處理操作,這是后話种柑。
2岗仑、ID讀卡器數(shù)據(jù)讀取界面和條碼掃描槍讀取界面的分析介紹
在我的會員管理系統(tǒng)里面,錄入卡號一般是通過ID讀卡器獲取的聚请,在界面上設(shè)置一個可以彈出錄入的文本框荠雕,也方便手工錄入卡號,如下面的界面功能所示驶赏。
當(dāng)然炸卑,有時候,我們可能不需要提供手工錄入煤傍,那么就不能通過光標錄入方式獲取掃描的內(nèi)容盖文,因為我們把輸入框設(shè)置為只讀的了,所以這種情況蚯姆,就就應(yīng)該通過事件來獲取設(shè)備的輸入內(nèi)容五续。
在條碼槍處理讀取條形碼或者二維碼的時候,我們一般都是和商品相關(guān)的地方使用條形碼龄恋,二維碼也可以使用疙驾,條形碼可能一般帶有數(shù)據(jù)供閱讀,二維碼則沒有篙挽,但是都可以通過設(shè)備讀取出來到文本框里面荆萤,一般如果錄入,就停放光標在文本框就可以了铣卡,如商品的信息的錄入链韭。在我們需要輸入條碼的地方點一下,然后操作條碼槍錄入條碼即可煮落,這種不需要額外的代碼處理敞峭。
但是對于一些我們需要快速錄入商品信息的界面,如客戶消費界面蝉仇,那么就需要對條碼的事件進行處理了旋讹。
例如下面的界面,在消費確認前的產(chǎn)品錄入轿衔,我們都是通過條碼槍的快速掃描產(chǎn)品進行錄入的沉迹,這時候條碼槍就代替了手工的錄入,我們可以每次掃描一次害驹,就在列表里面自動增加一個對應(yīng)商品的記錄鞭呕,非常方便的了。
3宛官、通用的讀卡操作和條碼掃描槍操作實現(xiàn)
在前面小節(jié)介紹了一些利用ID讀卡器錄入數(shù)據(jù)和使用條碼槍的場景葫松,對于如果是在可輸入文本框里面獲得內(nèi)容,不用任何編碼底洗,如果是在只讀界面或者窗體上獲得設(shè)備的數(shù)據(jù)腋么,那么就可以通過事件進行處理了,那么讀卡器和掃描槍的事件應(yīng)該如何處理的呢亥揖。
我的做法珊擂,是統(tǒng)一在我的Winform開發(fā)框架的界面層基類模塊里面,增加一些硬件相關(guān)的處理類和界面费变,這樣在各個框架派生出來的項目就可以很方便使用了摧扇。
其中Device里面的CardReader就是IC、ID讀卡器獲取操作的處理胡控,一般來說扳剿,這些卡都是以00開始的,所以我們的處理類昼激,通過一個Time來控制連續(xù)獲取數(shù)據(jù)的處理就可以了庇绽,主要就是監(jiān)聽KeyUp事件。
以CardReader為例橙困,它的完整代碼如下所示瞧掺。
/// <summary>
/// 讀卡器封裝類
/// </summary>
public class CardReader
{
private Control _hostCtrl;
private string _cardCode;
private Timer _timer;
private const int CARD_CODE_LEN = 10;
private const string CARD_CODE_START = "00";
/// <summary>
/// 讀卡器讀到一張卡的事件
/// </summary>
public event CardReadEventHandler CardRead;
/// <summary>
/// 默認讀卡器(掛在主窗體上,會被主窗體初始化凡傅,在模塊里用肯定是安全的)
/// </summary>
public static CardReader Default { get; set; }
/// <summary>
/// 構(gòu)造器
/// </summary>
/// <param name="hostCtrl">接受鍵盤事件的宿主控件</param>
public CardReader(Control hostCtrl)
{
_hostCtrl = hostCtrl;
if (_hostCtrl is Form)
{
(_hostCtrl as Form).KeyPreview = true;
}
_hostCtrl.KeyUp += new KeyEventHandler(hostCtrl_KeyUp);
_cardCode = "";
_timer = new Timer();
_timer.Interval = 20;
_timer.Tick += new EventHandler(timer_Tick);
_timer.Start();
}
/// <summary>
/// 判斷是否卡號
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
public static bool IsCardCode(string code)
{
return code.Length == CARD_CODE_LEN && code.StartsWith(CARD_CODE_START);
}
/// <summary>
/// 定時器到期的事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void timer_Tick(object sender, EventArgs e)
{
//達到一定的位數(shù)才開始判斷
if (_cardCode.Length >= CARD_CODE_LEN)
{
_cardCode = _cardCode.Trim((char)13);
if (IsCardCode(_cardCode))
{
_timer.Stop();
OnCardRead(_cardCode);
}
}
_cardCode = "";
_timer.Start();
}
/// <summary>
/// 監(jiān)聽按鍵彈起的事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void hostCtrl_KeyUp(object sender, KeyEventArgs e)
{
_timer.Stop();
_cardCode = _cardCode + (char)e.KeyValue;
_timer.Start();
}
private void OnCardRead(string scanCode)
{
if (CardRead != null)
{
CardRead(scanCode);
}
}
}
/// <summary>
/// 讀卡器讀到一張卡的事件處理委托
/// </summary>
/// <param name="cardCode"></param>
public delegate void CardReadEventHandler(string cardCode);
CardReader封裝類辟狈, 它的使用操作如下所示。我們通過事件就可以獲取到完整的輸入內(nèi)容,然后進行數(shù)據(jù)的綁定或處理即可哼转,代碼如下所示明未。
public partial class FrmProcessConsumption : BaseDock
{
/// <summary>
/// 會員信息
/// </summary>
private MemberInfo memberInfo { get; set; }
/// <summary>
/// 讀卡器接口
/// </summary>
private CardReader cardReader;
public FrmProcessConsumption()
{
InitializeComponent();
................................
cardReader = new CardReader(this);
cardReader.CardRead += new CardReadEventHandler(cardReader_CardRead);
}
void cardReader_CardRead(string cardCode)
{
this.txtMember_CardNo.Text = cardCode;
BindMemberData();
}
然后我們?yōu)榱朔奖闶褂茫€可以定義一個統(tǒng)一的處理讀卡器和掃描槍的接收數(shù)據(jù)的小窗口壹蔓。
這個彈出的小窗口用來處理讀卡器趟妥,掃描槍等信息的錄入就可以了,當(dāng)然上述的如CardReader/USBScanner還是可以獨立使用佣蓉,如我們在一個只讀控件或者窗口里面披摄,一樣可以監(jiān)聽到對應(yīng)的設(shè)備數(shù)據(jù)讀取操作,但設(shè)備有數(shù)據(jù)讀取完成過后勇凭,就會觸發(fā)相應(yīng)的事件了疚膊。
下面代碼就是上面設(shè)備信息讀取的代碼
/// <summary>
/// 讀卡器、USB條碼掃描器虾标、串口條碼掃描器數(shù)據(jù)讀取及顯示窗體
/// </summary>
public partial class DeviceReaderDialog : BaseForm
{
private CardReader _cardReader;
private USBScanner _usbScanner;public DeviceReaderDialog(DeviceType type = DeviceType.Card)
{
InitializeComponent();
//能手填
this.Readonly = false;
if (type == DeviceType.Card)
{
this._cardReader = new CardReader(this);
this._cardReader.CardRead += new CardReadEventHandler(_cardReader_CardRead);
}
else if (type == DeviceType.UsbScanner)
{
this._usbScanner = new USBScanner(this);
this._usbScanner.ScannerRead += new ScannerReadEventHandler(Scanner_ScannerRead);
}
}
void Scanner_ScannerRead(string scanCode)
{
this.txtCode.Text = scanCode;
DialogResult = DialogResult.OK;
}
void _cardReader_CardRead(string cardCode)
{
this.txtCode.Text = cardCode;
DialogResult = DialogResult.OK;
}
public string Code
{
get { return txtCode.Text; }
}
public bool Readonly
{
get { return txtCode.Properties.ReadOnly; }
set
{
txtCode.Properties.ReadOnly = value;
this.btnOK.Enabled = !value;
this.btnOK.Visible = !value;
}
}
private void DeviceReaderDialog_Load(object sender, EventArgs e)
{
if (!this.Readonly)
{
this.KeyDown += new KeyEventHandler(DeviceReaderDialog_KeyDown);
}
}
void DeviceReaderDialog_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
this.DialogResult = DialogResult.OK;
}
}
}