【问题标题】:C# BarCode Scanning Program won't Accept Alphabetic CharactersC# 条码扫描程序不接受字母字符
【发布时间】:2019-04-10 05:06:03
【问题描述】:

我有一些用 C# 编写的代码,允许用户扫描条形码,并且 label.Text 更改为条形码的输入。我使用标签而不是文本框来防止用户使用错误的条形码 - 基本上禁用任何键盘输入。

一切都很好,除非被扫描的条形码中有字母字符。如果条形码以字母字符开头并以字母字符结尾,则条形码根本不扫描。

如果条形码以字母字符开头,但以数字字符结尾,则程序仅拾取结尾的数字字符。

代码如下:

    char cforKeyDown = '\0';
    int _lastKeystroke = DateTime.Now.Millisecond;
    List<char> _barcode = new List<char>();
    bool UseKeyboard = false;

  private void Form1_Load(object sender, EventArgs e)
    {
        this.ActiveControl = label1;
        this.KeyDown += new KeyEventHandler(Form1_KeyDown);
        this.KeyUp += new KeyEventHandler(Form1_KeyUp);
    }
 private void Form1_KeyUp(object sender, KeyEventArgs e)
    {
        // if keyboard input is allowed to read
        if (UseKeyboard && e.KeyData != Keys.Enter)
        {
            MessageBox.Show(e.KeyData.ToString());
        }

        /* check if keydown and keyup is not different
         * and keydown event is not fired again before the keyup event fired for the same key
         * and keydown is not null
         * Barcode never fired keydown event more than 1 time before the same key fired keyup event
         * Barcode generally finishes all events (like keydown > keypress > keyup) of single key at a time, if two different keys are pressed then it is with keyboard
         */

        if (cforKeyDown != (char) e.KeyCode || cforKeyDown == '\0')
        {
            cforKeyDown = '\0';
            _barcode.Clear();
            return;
        }

        // getting the time difference between 2 keys
        int elapsed = (DateTime.Now.Millisecond - _lastKeystroke);

        /*
         * Barcode scanner usually takes less than 17 milliseconds to read, increase this if neccessary of your barcode scanner is slower
         * also assuming human can not type faster than 17 milliseconds
         */
        // Bumped it up to 35[ms]
        if (elapsed > 50)
            _barcode.Clear();

        // Do not push in array if Enter/Return is pressed, since it is not any Character that need to be read
        if (e.KeyCode != Keys.Return)
        {
            //_barcode.Add((char) e.KeyData);
            _barcode.Add((char) e.KeyData);
        }

        // Barcode scanner hits Enter/Return after reading barcode
        if (e.KeyCode == Keys.Return && _barcode.Count > 0)
        {
            string BarCodeData = new String(_barcode.ToArray());

            if (!UseKeyboard)
            {
                //MessageBox.Show(String.Format("{0}", BarCodeData));
                label1.Text = String.Format("{0}", BarCodeData);
            }
            //_barcode.Clear();
        }
        // update the last key stroke time
        _lastKeystroke = DateTime.Now.Millisecond;
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        //Debug.WriteLine("CS_Single_Label_Printer_KeyDown : " + (char)e.KeyCode);
        cforKeyDown = (char) e.KeyCode;
    }

我已将问题缩小到正在扫描的字母数字条形码的字母部分是大写的事实。我使用小写字母生成了一个测试条形码,一切正常,但这仍然不能解决问题,因为我必须扫描数千个已打印的条形码,这些条形码将大写字符编码到条形码数据矩阵中。

有没有办法切换上面的代码来解释'字符 | Shift 键数据?

【问题讨论】:

  • 请问您使用的是什么型号的条码扫描器?
  • 我们使用了一整套扫描仪。目前,我正在使用 Honeywell 4600g 测试该程序,但我们也有 Symbols,最常见的是 DS6707。
  • 您应该能够配置条码扫描器,通过配置条码将所有大写字母转换为小写字母,反之亦然 - 请参阅此处了解 Honeywell support.honeywellaidc.com/s/article/…

标签: c# keypress barcode-scanner


【解决方案1】:

答案是 KeyCode 返回按下的 KEY。它不尊重密钥的大小写。使用 Shift 来获取案例。下面是一个基于您提供的代码的工作示例。神奇之处在于本地函数 ToCharacter。如果您愿意的话,您还需要使用顶部的 if 语句来包含数字。

From1.cs

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace DesktopApp2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        char cforKeyDown = '\0';
        int _lastKeystroke = DateTime.Now.Millisecond;
        List<char> _barcode = new List<char>();
        bool UseKeyboard = false;

        private void Form1_Load(object sender, EventArgs e)
        {
            this.ActiveControl = InputBox;
            this.InputBox.KeyDown += new KeyEventHandler(Form1_KeyDown);
            this.InputBox.KeyUp += new KeyEventHandler(Form1_KeyUp);
        }
        private void Form1_KeyUp(object sender, KeyEventArgs e)
        {
            char NotALetter = '-';

            DebugBox.Items.Clear();
            DebugBox.Items.Add($"KeyEventArgs->KeyCode = {e.KeyCode.ToString()}");
            DebugBox.Items.Add($"KeyEventArgs->KeyData = {e.KeyData.ToString()}");
            DebugBox.Items.Add($"KeyEventArgs->KeyValue = {e.KeyValue.ToString()}");
            DebugBox.Items.Add($"KeyEventArgs->e.Shift = {e.Shift.ToString()}");
            DebugBox.Items.Add($"ToCharacter = {ToCharacter(e) ?? NotALetter}");


            char? ToCharacter(KeyEventArgs kea)
            {
                int DtoNumPadOffset = (int)(Keys.NumPad0 - Keys.D0);
                if (kea.KeyCode < Keys.D0) return null; // Keys.D0 through Kyes.D9 are the Keys on the top row of the keyboard. D9 is right next to A in the enum type. 
                if (kea.KeyCode > Keys.NumPad9) return null;
                if (kea.KeyCode > Keys.Z && kea.KeyCode < Keys.NumPad0) return null; //knocks out keys between Z and NumPad0
                if (kea.Shift && kea.KeyCode < Keys.A) return null; // rejects special characters when numbers across the top are used with the <shift> key.

                if (kea.KeyCode < Keys.A) return (char)kea.KeyCode;
                if (kea.KeyCode > Keys.Z) return (char)((int)kea.KeyCode - DtoNumPadOffset);

                return kea.Shift
                    ? (char)kea.KeyCode
                    : char.ToLower((char)kea.KeyCode);
            }


            // if keyboard input is allowed to read
            if (UseKeyboard && e.KeyData != Keys.Enter)
            {
                MessageBox.Show(e.KeyData.ToString());
            }

            /* check if keydown and keyup is not different
             * and keydown event is not fired again before the keyup event fired for the same key
             * and keydown is not null
             * Barcode never fired keydown event more than 1 time before the same key fired keyup event
             * Barcode generally finishes all events (like keydown > keypress > keyup) of single key at a time, if two different keys are pressed then it is with keyboard
             */

            //if (cforKeyDown != (char)e.KeyCode || cforKeyDown == '\0')
            //{
            //    cforKeyDown = '\0';
            //    _barcode.Clear();
            //    return;
            //}

            // getting the time difference between 2 keys
            int elapsed = (DateTime.Now.Millisecond - _lastKeystroke);

            /*
             * Barcode scanner usually takes less than 17 milliseconds to read, increase this if neccessary of your barcode scanner is slower
             * also assuming human can not type faster than 17 milliseconds
             */
            // Bumped it up to 35[ms]
            //if (elapsed > 2000)
            if (e.KeyCode == Keys.Return)
            {
                InputBox.Text = String.Empty;
                _barcode.Clear();
            }

            // Do not push in array if Enter/Return is pressed, since it is not any Character that need to be read
            if (e.KeyCode != Keys.Return)
            {
                char? TestForCharacter = ToCharacter(e);

                if (TestForCharacter != null)
                {
                    //_barcode.Add((char) e.KeyData);
                    _barcode.Add((char)TestForCharacter);
                }
            }

            OutputBox.Text = string.Concat(_barcode);

            // Barcode scanner hits Enter/Return after reading barcode
            if (e.KeyCode == Keys.Return && _barcode.Count > 0)
            {
                string BarCodeData = new String(_barcode.ToArray());

                if (!UseKeyboard)
                {
                    //MessageBox.Show(String.Format("{0}", BarCodeData));
                    OutputBox.Text = String.Format("{0}", BarCodeData);
                }
                //_barcode.Clear();
            }
            // update the last key stroke time
            _lastKeystroke = DateTime.Now.Millisecond;
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            //Debug.WriteLine("CS_Single_Label_Printer_KeyDown : " + (char)e.KeyCode);
            cforKeyDown = (char)e.KeyCode;
        }
    }
}

Form1.Designer.cs

namespace DesktopApp2
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.OutputBox = new System.Windows.Forms.TextBox();
            this.InputBox = new System.Windows.Forms.TextBox();
            this.DebugBox = new System.Windows.Forms.ListBox();
            this.SuspendLayout();
            // 
            // OutputBox
            // 
            this.OutputBox.Location = new System.Drawing.Point(52, 93);
            this.OutputBox.Name = "OutputBox";
            this.OutputBox.ReadOnly = true;
            this.OutputBox.Size = new System.Drawing.Size(650, 22);
            this.OutputBox.TabIndex = 1;
            // 
            // InputBox
            // 
            this.InputBox.Location = new System.Drawing.Point(52, 45);
            this.InputBox.Name = "InputBox";
            this.InputBox.Size = new System.Drawing.Size(650, 22);
            this.InputBox.TabIndex = 2;
            // 
            // DebugBox
            // 
            this.DebugBox.FormattingEnabled = true;
            this.DebugBox.ItemHeight = 16;
            this.DebugBox.Location = new System.Drawing.Point(52, 131);
            this.DebugBox.Name = "DebugBox";
            this.DebugBox.Size = new System.Drawing.Size(650, 308);
            this.DebugBox.TabIndex = 3;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(716, 450);
            this.Controls.Add(this.DebugBox);
            this.Controls.Add(this.InputBox);
            this.Controls.Add(this.OutputBox);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion
        private System.Windows.Forms.TextBox OutputBox;
        private System.Windows.Forms.TextBox InputBox;
        private System.Windows.Forms.ListBox DebugBox;
    }
}

用于处理 KeyEventArgs 的整洁的辅助类
Is* 函数将键码分组为范围并检测(如果适用)换档状态。 To* 函数生成最能代表事件中 KeyCode 的字符。 ToAlphaNumericAsciiCharacter 只是将检测器与生产者配对。

public static class KeyEventArgs_Functions
{
    public static bool Between(this Keys source, Keys lhv, Keys rhv)
    {
        return source >= lhv && source <= rhv;
    }
    public static bool IsLetterKeyBoardChar(this KeyEventArgs source)
    {
        return source.KeyCode.Between(Keys.A, Keys.Z);
    }
    public static bool IsNumberKeyBoardChar(this KeyEventArgs source)
    {
        return !source.Shift && source.KeyCode.Between(Keys.D0, Keys.D9);
    }
    public static bool IsNumber10KeyPadChar(this KeyEventArgs source)
    {
        return source.KeyCode.Between(Keys.NumPad0, Keys.NumPad9);
    }
    public static char ToLetterKeyBoardChar(this KeyEventArgs source) // Only returns a valid value if IsLetterKeyBoardChar returns true.
    {
       return source.Shift ? (char)source.KeyCode: char.ToLower((char)source.KeyCode);
    }
    public static char ToNumberKeyBoardChar(this KeyEventArgs source) // Only returns a valid value if IsNumberKeyBoardChar returns true.
    {
        return (char)source.KeyCode;
    }
    public static char ToNumber10KeyPadChar(this KeyEventArgs source) // Only returns a valid value if IsNumber10KeyPadChar returns true.
    {
        const int DtoNumPadOffset = (int)(Keys.NumPad0 - Keys.D0);
        return (char)((int)source.KeyCode - DtoNumPadOffset);
    }
    public static char? ToAlphaNumericAsciiCharacter(this KeyEventArgs source)
    {
        if (source.IsLetterKeyBoardChar()) return source.ToLetterKeyBoardChar();
        if (source.IsNumberKeyBoardChar()) return source.ToNumberKeyBoardChar();
        if (source.IsNumber10KeyPadChar()) return source.ToNumber10KeyPadChar();
        return null;
    }
}

【讨论】:

  • 感谢您的帮助!该程序仍然给我相同类型的行为,即您的 InputBox 扫描正确的代码(例如 NF6000036),但您的 OutputBox 会显示 6000036。另外,也许微不足道,我想坚持使用标签而不是一个文本框。 (有趣的是,当我将 InputBox 设置为只读时,它的行为与 OutputBox 相同。)
  • @DanielPavlovsky,我稍微修改了这个例子,因为我没有扫描仪,我让它对键盘更友好。重要的变化是我修改了 ToCharacter 以返回 [A-Za-z0-9],然后我将它输入到条形码对象中。
  • 感谢您的帮助。虽然我不得不稍微改变一下你的代码,但它提供了一个很好的基础。
  • @DanielPavlovsky,很高兴为您提供帮助。所以我知道,你需要改变什么?
  • 这与我在原始查询中所要求的实际功能无关。只是为了方便起见,我需要程序在标签被扫描后立即打印标签,所以你可以连续扫描一百个条形码,它会自动打印它们。为了适应这种情况,我只需要摆脱 DebugBox 并将一些 .Focus() 和 .SelectAll() 添加到我自己的一些代码中,即原始帖子中未包含的内容。再次感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多