我正在尝试使Windows窗体应用程序能够重复显示然后隐藏自己。
这个想法是创建一个小应用程序,每次按下Num Lock或Caps lock等修饰键时,它会覆盖屏幕上的图像。我检测到键盘按键完美无缺,但是我创建一个可以显示然后反复隐藏的表单并没有太多运气。
我看到的方式,(如果我错了,请纠正我)有两种方法可以让表单表现得像我想要的那样:
Program.cs
中启动表单,然后保留逻辑以隐藏和显示表单并在Form1.cs
中显示图像
this.Hide()
和this.Show()
来隐藏和显示自己,但每当我尝试这样做时,我都无法让this.Hide()
隐藏表单;在所有打开的窗户顶部,表格仍然可见。Program.cs
中显示表单的逻辑,然后按住逻辑以在Form1.cs
中显示图像
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;
}
}
}
}
答案 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);
}
}