0

我有一个文本框和一个列表框。Shift必须清除列表框,Shift+Del组合必须清除文本框。

这是我的代码。

private void MainForm_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Shift && e.KeyCode == Keys.Delete) textBox.Clear();
    if (e.Shift) listBox.Items.Clear();
}

它显然是错误的,因为列表框在关闭时总是被清除Shift。我需要能够通过按Shift+来清除文本框,Del而不是当时清除列表框。

我必须只使用ShiftDel键,而不能使用其他键。

那我该怎么办?

4

2 回答 2

0

首先,让我先说一下,我通常建议不要Shift单独使用密钥来触发任何桌面软件中的动作,而不是游戏。这样做违反了最小惊讶原则:由于Shift在正常打字过程中经常使用它来修改其他键的含义,因此用户习惯于期望按下它本身不会产生任何后果,当然也不会造成任何破坏。因此,如果用户不经意地按下Shift并发现他刚刚丢失了他的项目列表,他可能会感到非常不愉快,特别是如果要恢复损坏是困难或乏味的。

但是,您在评论中说您在这件事上别无选择,所以说,这是一个可能的解决方案。

为了能够区分单独ShiftShift+Del组合之间的区别,我们需要捕获KeyDown事件并KeyUp使用从每个事件中收集的信息。

在这种情况KeyDown下,我们将 的值保存KeyEventArgs.KeyData到一个私有字段,但尚未对其采取任何操作。 KeyData包含Keys表示被按下的主键的组合标志,以及任何修改键,如Ctrl,ShiftAlt同时被按住。注意当Shift被单独按下时,它既是主键是修饰符,所以KeyData会包含Keys.ShiftKey(键)和Keys.Shift(修饰符)的组合。

private Keys LastKeysDown;

private void MainForm_KeyDown(object sender, KeyEventArgs e)
{
    LastKeysDown = e.KeyData;
}

在这种情况KeyUp下,我们会查看相对于上次按下的键释放了哪些键。我们正在寻找两个特定的键序列:

  1. Shift+Del被按下,然后在仍被按住Del时被释放。Shift
  2. Shift在没有其他键的情况下按下,然后释放。

如果我们找到了我们正在寻找的东西,我们就会启动适当的操作,否则我们什么也不做。

private void MainForm_KeyUp(object sender, KeyEventArgs e)
{
    // Shift + Delete pressed, then Delete released while Shift still held down
    if (LastKeysDown == (Keys.Shift | Keys.Delete) && e.KeyData == LastKeysDown)
        textBox1.Clear();

    // Shift pressed with no other key, then released
    else if (LastKeysDown == (Keys.Shift | Keys.ShiftKey) && e.KeyData == Keys.ShiftKey)
        listBox1.Items.Clear();

    LastKeysDown = Keys.None;
}

请注意,作为最后的任务,我们清除私有LastKeysDown字段。这有助于确保如果我们KeyUp连续获得两个事件,则只有第一个与前一个配对KeyDown。但请注意,这并非万无一失:如果您按住按键的时间足够长,计算机的按键重复将启动并产生额外的KeyDown事件。

于 2017-11-24T07:07:31.310 回答
-1

如果您只想依赖,Key_Down您可以使用一个BackgroundWorker(或 Timer 也可以)在清除列表之前等待几毫秒。如果在此期间有另一个密钥进入,则取消 BackgroundWorker。您的实现可能如下所示:

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Shift && 
        e.KeyCode == Keys.Delete)
    {
        if (backgroundWorker1.IsBusy)
        {
            Trace.WriteLine("cancelling");
            backgroundWorker1.CancelAsync();
        }
        textBox.Clear();
    }

    if (e.Shift && 
        e.KeyCode == Keys.ShiftKey && 
        !backgroundWorker1.IsBusy)
    {
        backgroundWorker1.RunWorkerAsync();
    }

}

private void  backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    e.Result = false;
    // wait 2 seconds (that is a bit long, adjust accordingly)
    Thread.Sleep(2000); // HACK, use a proper timer here
    // tell RunWorkerCompleted if we're good to clear
    e.Result = !backgroundWorker1.CancellationPending;
}

// this gets called on the UI thread
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Trace.WriteLine(String.Format("{0} - {1}", e.Cancelled, e.Result));
    if ((bool) e.Result)
    {
        listBox.Items.Clear();
    }
}

如果您还可以利用 KeyUp 事件,解决方案将变得更加容易:

private bool onlyShift = false; // keeps shift state

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    // becomes true if this is the shift key pressed
    onlyShift = e.Shift && e.KeyCode == Keys.ShiftKey;

    if (e.Shift && 
        e.KeyCode == Keys.Delete)
    {
        textBox.Clear();
    }               
}

private void Form1_KeyUp(object sender, KeyEventArgs e)
{
    // was the shiftkey the last one in keydown AND
    // are we releasing the shiftkey now
    if (onlyShift && e.KeyCode == Keys.ShiftKey)
    {
         listBox.Items.Clear();
    }
}

我个人会使用后一种解决方案。

于 2017-11-23T08:27:17.830 回答