Winform開發(fā)框架之讀卡器和條碼掃描槍的數(shù)據(jù)接收處理

在我們開發(fā)一些項(xiàng)目的時(shí)候,一般需要一些外圍的設(shè)備進(jìn)行數(shù)據(jù)處理,如ID/IC讀卡器獲取卡號、激光條碼掃描槍、USB攝像頭、USB方式的小票據(jù)打印機(jī)(POS打印機(jī))、USB來電錄音盒、普通打印機(jī)等一系列附屬設(shè)備。借助這些設(shè)備,可以使我們的業(yè)務(wù)流程更嚴(yán)謹(jǐn),輸入數(shù)據(jù)更方便,或者能夠一些特殊的數(shù)據(jù)等功能。本文主要介紹其中的ID讀卡器(IC讀卡器)快速讀取卡號,以及實(shí)用激光條碼槍的條碼掃描錄入功能,后面的一些硬件設(shè)備的處理,后續(xù)文章在繼續(xù)介紹。

1、設(shè)備介紹

前面介紹的設(shè)備,在很多場合上都可能用到,如我的會(huì)員管理系統(tǒng)里面,就需要用到下面的設(shè)備處理。



本文主要針對性了解ID讀卡器和條碼槍的設(shè)備數(shù)據(jù)處理,這兩種設(shè)備雖然不同,但是它們相似的地方就是都支持在光標(biāo)處錄入數(shù)據(jù)的,就有點(diǎn)類似我們的鍵盤快速錄入一樣,當(dāng)然激光條碼槍也支持很多種方式的事件處理操作,這是后話。

2、ID讀卡器數(shù)據(jù)讀取界面和條碼掃描槍讀取界面的分析介紹

在我的會(huì)員管理系統(tǒng)里面,錄入卡號一般是通過ID讀卡器獲取的,在界面上設(shè)置一個(gè)可以彈出錄入的文本框,也方便手工錄入卡號,如下面的界面功能所示。



當(dāng)然,有時(shí)候,我們可能不需要提供手工錄入,那么就不能通過光標(biāo)錄入方式獲取掃描的內(nèi)容,因?yàn)槲覀儼演斎肟蛟O(shè)置為只讀的了,所以這種情況,就就應(yīng)該通過事件來獲取設(shè)備的輸入內(nèi)容。



在條碼槍處理讀取條形碼或者二維碼的時(shí)候,我們一般都是和商品相關(guān)的地方使用條形碼,二維碼也可以使用,條形碼可能一般帶有數(shù)據(jù)供閱讀,二維碼則沒有,但是都可以通過設(shè)備讀取出來到文本框里面,一般如果錄入,就停放光標(biāo)在文本框就可以了,如商品的信息的錄入。在我們需要輸入條碼的地方點(diǎn)一下,然后操作條碼槍錄入條碼即可,這種不需要額外的代碼處理。

但是對于一些我們需要快速錄入商品信息的界面,如客戶消費(fèi)界面,那么就需要對條碼的事件進(jìn)行處理了。
例如下面的界面,在消費(fèi)確認(rèn)前的產(chǎn)品錄入,我們都是通過條碼槍的快速掃描產(chǎn)品進(jìn)行錄入的,這時(shí)候條碼槍就代替了手工的錄入,我們可以每次掃描一次,就在列表里面自動(dòng)增加一個(gè)對應(yīng)商品的記錄,非常方便的了。


3、通用的讀卡操作和條碼掃描槍操作實(shí)現(xiàn)

在前面小節(jié)介紹了一些利用ID讀卡器錄入數(shù)據(jù)和使用條碼槍的場景,對于如果是在可輸入文本框里面獲得內(nèi)容,不用任何編碼,如果是在只讀界面或者窗體上獲得設(shè)備的數(shù)據(jù),那么就可以通過事件進(jìn)行處理了,那么讀卡器和掃描槍的事件應(yīng)該如何處理的呢。
我的做法,是統(tǒng)一在我的Winform開發(fā)框架的界面層基類模塊里面,增加一些硬件相關(guān)的處理類和界面,這樣在各個(gè)框架派生出來的項(xiàng)目就可以很方便使用了。



其中Device里面的CardReader就是IC、ID讀卡器獲取操作的處理,一般來說,這些卡都是以00開始的,所以我們的處理類,通過一個(gè)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>
    /// 默認(rèn)讀卡器(掛在主窗體上,會(huì)被主窗體初始化,在模塊里用肯定是安全的)
    /// </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>
    /// 定時(shí)器到期的事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void timer_Tick(object sender, EventArgs e)
    {
        //達(dá)到一定的位數(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)容,然后進(jìn)行數(shù)據(jù)的綁定或處理即可,代碼如下所示。

public partial class FrmProcessConsumption : BaseDock
{
    /// <summary>
    /// 會(huì)員信息
    /// </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)榱朔奖闶褂?,還可以定義一個(gè)統(tǒng)一的處理讀卡器和掃描槍的接收數(shù)據(jù)的小窗口。



這個(gè)彈出的小窗口用來處理讀卡器,掃描槍等信息的錄入就可以了,當(dāng)然上述的如CardReader/USBScanner還是可以獨(dú)立使用,如我們在一個(gè)只讀控件或者窗口里面,一樣可以監(jiān)聽到對應(yīng)的設(shè)備數(shù)據(jù)讀取操作,但設(shè)備有數(shù)據(jù)讀取完成過后,就會(huì)觸發(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;
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 0x00 概述 許多提供NFC功能的基于Android的設(shè)備已經(jīng)支持NFC卡模擬。在大多數(shù)情況下,該卡由設(shè)備中的單...
    Killshadow閱讀 13,448評論 2 8
  • 到了境外,發(fā)現(xiàn)我的短信發(fā)不出去了,哎呀,沒有開通國際漫游,電話卡沒有信號了。 這件事很糟糕,剛剛體檢完,體檢結(jié)...
    工作與養(yǎng)娃兼顧的女人閱讀 1,035評論 0 0
  • 柴先生,在一起的第五天。 希望,我們一直愛下去。
    沙漏倒裝記憶閱讀 215評論 0 0
  • 我喜歡坐著公交出門看看,幾塊錢可以去很多地方,可以對一個(gè)地方有著新的認(rèn)識,對自己也算是種放松。 平時(shí)忙忙碌碌好不容...
    都市和尚閱讀 220評論 0 0

友情鏈接更多精彩內(nèi)容