C#make form hide然后重新显示

时间:2018-02-28 06:02:18

标签: c# winforms

我正在尝试使Windows窗体应用程序能够重复显示然后隐藏自己。

这个想法是创建一个小应用程序,每次按下Num Lock或Caps lock等修饰键时,它会覆盖屏幕上的图像。我检测到键盘按键完美无缺,但是我创建一个可以显示然后反复隐藏的表单并没有太多运气。

我看到的方式,(如果我错了,请纠正我)有两种方法可以让表单表现得像我想要的那样:

  • 通常在Program.cs中启动表单,然后保留逻辑以隐藏和显示表单并在Form1.cs中显示图像
    • 表单会调用this.Hide()this.Show()来隐藏和显示自己,但每当我尝试这样做时,我都无法让this.Hide()隐藏表单;在所有打开的窗户顶部,表格仍然可见。
  • 保留隐藏并在Program.cs中显示表单的逻辑,然后按住逻辑以在Form1.cs中显示图像
    • 我一直在使用the code from this guide来展示和隐藏来自Program.cs的来自表单的类包装器,但事实证明,form.Showdialog()阻止任何进一步执行代码,直到表单关闭。

我自己一直在玩代码,上述方法都没有奏效。我是否以错误的方式思考这个问题? WFA能否以我想要的方式行事?

这个代码有点混乱,我不确定哪些部分最相关,但我会尽力把它包含在这里:

Program.cs的

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Forms;

namespace KeyboardIndicators {
  // ApplicationContext wrapper
  public abstract class TrayIconApplicationContext : ApplicationContext {
    private NotifyIcon lockIcon;
    private ContextMenu lockIconContext;

    protected TrayIconApplicationContext() {
      // Wire up the ApplicationExitHandler to ApplicationExit events
      Application.ApplicationExit += this.ApplicationExitHandler;

      lockIconContext = new ContextMenu {

      };

      // Create lockIcon tray icon and make it visible
      lockIcon = new NotifyIcon {
        ContextMenu = lockIconContext,
        Text = Application.ProductName,
        Icon = new Icon("icon.ico"),
        Visible = true
      };

    }

    protected NotifyIcon LockIcon { get { return lockIcon; } }
    protected ContextMenu LockIconContext { get { return lockIconContext; } }


    // ApplicationExit event handler
    private void ApplicationExitHandler(object sender, EventArgs e) {
      this.OnApplicationExit(e);
    }

    // Performs cleanup to end the application
    protected virtual void OnApplicationExit(EventArgs e) {
      // TODO(Neil): Add meaningful thread cleanup here soon
      if (lockIcon != null) {
        lockIcon.Visible = false;
        lockIcon.Dispose();
      }
      if (lockIconContext != null)
        LockIconContext.Dispose();
    }
  }

  // TrayIconApplicationContext wrapper for Form1 to control the activation of the form window
  class FormApplicationContext : TrayIconApplicationContext {
    public FormApplicationContext() {
      // Add Exit menu item
      MenuItem exit = new MenuItem("E&xit");
      this.LockIconContext.MenuItems.Add(exit);
      exit.Click += this.ExitContextMenuClickHandler;

      //KeyboardIndicators indicators = new KeyboardIndicators();
      //indicators.RunListener();

      {
        using(Form form = new Form1("NumLock", true))
          form.ShowDialog();
      }
    }

    private void ExitContextMenuClickHandler(object sender, EventArgs eventArgs) {
      this.ExitThread();
    }
  }

  public class KeyboardIndicators {
    class LockState {
      // Is the numlock key on?
      public bool Num;
      // Is the capslock key on?
      public bool Caps;
      // Is the scroll lock key on?
      public bool Scroll;
    }

    public void RunListener() {
      try {
        // Store the old keyboard lock state
        LockState prevState = new LockState() {
          Num = Control.IsKeyLocked(Keys.NumLock),
          Caps = Control.IsKeyLocked(Keys.CapsLock),
          Scroll = Control.IsKeyLocked(Keys.Scroll)
        };

        while (true) {
          // Store the new keyboard lock state
          LockState newState = new LockState() {
            Num = Control.IsKeyLocked(Keys.NumLock),
            Caps = Control.IsKeyLocked(Keys.CapsLock),
            Scroll = Control.IsKeyLocked(Keys.Scroll)
          };

          //TODO(Neil): Handle simultaneous presses better, i.e. queue the balloon tips
          if (newState.Num != prevState.Num) {
            Form1 form = new Form1("NumLock", newState.Num);
          } else if (newState.Caps != prevState.Caps) {
            Form1 form = new Form1("CapsLock", newState.Caps);
          } else if (newState.Scroll != prevState.Scroll) {
            Form1 form = new Form1("ScrollLock", newState.Scroll);
          }

          // Set the previous lock state to the new one in prep for the next iteration
          prevState = newState;

          // Sleep for 500ms
          Thread.Sleep(500);
        }
      } catch (ThreadAbortException) { /* No need to do anything, just catch the ThreadAbortException.*/ }
    }
  }

  static class Program {
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main() {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);

      //Application.Run(new Form1("NumLock", true));
      Application.Run(new FormApplicationContext());
    }
  }
}

Form1.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;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace KeyboardIndicators {
  public partial class Form1 : Form {
    public Form1(String activatedModifier, bool lockState) {
      InitializeComponent();
      ShowForm(activatedModifier);

      //this.Show();
      //this.Hide();
    }

    public void ShowForm(String activatedModifier) {
      PictureBox pictureBox = new PictureBox();

      Image myBitmap = Image.FromFile("cube.png");
      Size bitmapSize = new Size(myBitmap.Width, myBitmap.Height);

      switch (activatedModifier) {
        case "NumLock":
          break;
        case "CapsLock":
          break;
        case "ScrollLock":
          break;
      }

      this.Size = bitmapSize;
      pictureBox.ClientSize = bitmapSize;

      pictureBox.Image = myBitmap;
      pictureBox.Dock = DockStyle.Fill;
      this.Controls.Add(pictureBox);
      this.FormBorderStyle = FormBorderStyle.None;
    }

    protected override CreateParams CreateParams {
      get {
        CreateParams createParams = base.CreateParams;
        createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT

        return createParams;
      }
    }
  }
}

1 个答案:

答案 0 :(得分:0)

作为示例,我创建了一个Winforms应用程序,如果按下任何键,则显示“NUM”和/或“CAPS”,否则表单将被隐藏。 密钥的检测基于C# Low Level Keyboard Hook

<强> Program.cs的

using System;
using System.Windows.Forms;

namespace WinFormsKeyHook
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

<强> Form1.cs的

注意:在Designer中向Form1添加名为“label1”的标签。

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

namespace WinFormsKeyHook
{
    public partial class Form1 : Form
    {
        private static bool _caps;
        private static bool _num;

        public Form1()
        {
            InitializeComponent();

            KeyboardHook kh = new KeyboardHook();
            kh.KeysToObserve.AddRange(new List<Keys> { Keys.CapsLock, Keys.NumLock });
            kh.InstallHook();
            kh.KeyDown = key => ProcessKeyDown(key);

            _caps = Control.IsKeyLocked(Keys.CapsLock);
            _num = Control.IsKeyLocked(Keys.NumLock);
        }

        private void ProcessKeyDown(Keys key)
        {

            if (key == Keys.CapsLock)
            {
                _caps = !_caps;
            }
            if (key == Keys.NumLock)
            {
                _num = !_num;
            }

            this.ShowState(_num, _caps);
        }

        internal void ShowState(bool num, bool caps)
        {
            if (!num && !caps)
            {
                this.Hide();
                return;
            }

            this.label1.Text = "";
            this.label1.Text += num ? "NUM " : "";
            this.label1.Text += caps ? "CAPS" : "";

            if (!this.Visible)
            {
                this.Show();
            }
        }
    }
}

<强> KeyboardHook.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WinFormsKeyHook
{
    public class KeyboardHook
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private IntPtr _hookID = IntPtr.Zero;

        public List<Keys> KeysToObserve { get; set; } = new List<Keys>();

        public Action<Keys> KeyDown;

        public void InstallHook()
        {
            _hookID = SetHook(HookCallback);
        }

        ~KeyboardHook()
        {
            UnhookWindowsHookEx(_hookID);
        }

        public IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        public IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
             if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                var key = (Keys)vkCode;
                Console.WriteLine(key);
                KeyDown(key);
            }

            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);
    }
}