В C# в Windows 11 у меня есть форма со сплошным фоном и прозрачным PictureBox
. Форма загружается, и PictureBox
на самом деле прозрачен, но когда я навожу указатель мыши на прозрачную область, обработка мыши передается объектам за формой.
Поскольку я хочу, чтобы форма обрабатывала события наведения курсора мыши на прозрачные области, я добавил переопределение для WndProc, которое перехватывает сообщение NCHITTEST и возвращает значение HTCLIENT, равное 1. Я думаю, что это правильно, основываясь на Документе сообщения Microsoft WM_NCHITTEST.
С помощью этого обновленного WndProc я могу видеть сообщения от Form_MouseMove
; но ни одного из PictureBox_MouseMove
. А объекты, видимые через прозрачный элемент за формой, управляют мышью.
Я подозреваю, что можно перехватить эти сообщения управления мышью и заставить мою форму обрабатывать их, но я не могу понять, как это сделать.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TransparentFormExample
{
public class TransparentForm : Form
{
private PictureBox pictureBox;
public TransparentForm()
{
// Set form properties
this.TransparencyKey = Color.LimeGreen;
this.Size = new Size(500, 800);
this.TopMost = true;
// Initialize and set PictureBox properties
pictureBox = new PictureBox
{
BackColor = Color.LimeGreen,
Size = new Size(200, 200),
Location = new Point(150, 300) // Centered in the form
};
// Add PictureBox to the form
this.Controls.Add(pictureBox);
// Add event handlers
this.MouseMove += new MouseEventHandler(Form_MouseMove);
pictureBox.MouseMove += new MouseEventHandler(PictureBox_MouseMove);
}
// Override WndProc to handle WM_NCHITTEST message
protected override void WndProc(ref Message m)
{
const int WM_NCHITTEST = 0x84;
const int HTCLIENT = 0x1;
if (m.Msg == WM_NCHITTEST)
{
m.Result = (IntPtr)HTCLIENT;
return;
}
base.WndProc(ref m);
}
private void Form_MouseMove(object sender, MouseEventArgs e)
{
Console.WriteLine("Mouse over form");
}
private void PictureBox_MouseMove(object sender, MouseEventArgs e)
{
// extra spaces to make it easier to spot if it happens
Console.WriteLine(" Mouse over PictureBox");
}
public void Start ()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
Application.Run( this );
}
}
}
Я запускаю форму с помощью следующей оболочки PowerShell, поскольку у меня нет возможности создавать DLL, компилировать .cs и запускать файлы .exe.
write-host "load main.cs"
add-type -path "TransparentForm.cs" -ReferencedAssemblies @(
"System.Windows.Forms"
"System.Drawing"
"System.Drawing.Primitives"
)
$ProgramInstance = [TransparentFormExample.TransparentForm]::New()
[System.Windows.Forms.Application]::Run( $ProgramInstance )
Это использование System.Windows.Forms
Для ваших нужд вы устанавливаете для PictureBox «BackColor» значение «Color.Transparent». Установка цвета TransparencyKey фактически заставляет его «исчезать».
Вы можете воспользоваться старой ошибкой в Win7+: использовать Color.Red для ключа прозрачности и заднего цвета pb.
При установке для PictureBox.BackColor значения Color.Transparent PictureBox становится прозрачным, но в результате вы видите сквозь PictureBox фон формы. Цель состоит в том, чтобы иметь возможность видеть другие окна через прозрачное отверстие в форме, но при этом сохранять контроль над мышью в форме.
Вы пробовали использовать Красный (вместо Лаймового), как предлагал Ганс Пассант?
@ Ненависть, да. Я попробовал Color.Red, и это привело к той же проблеме.
@RoYoMi Я попробовал это на Win8, и красный трюк сработал. Другая идея — очистить экран рабочего стола (за исключением формы), а затем нарисовать содержимое PictureBox. Или вы можете встроить элемент управления WPF.
@RoYoMi Пример для WPF: прозрачное плавающее окно, которое остается за формой и фиксирует события мыши.
Начиная как минимум с Windows 11, прозрачные элементы в System.Windows.Forms не получают события мыши. Даже если вы создаете собственный метод переопределения WndProc. Этот метод не вызывается, когда указатель мыши находится над прозрачным элементом.
Возможно, это новая ошибка, или они изменили, какая функция вызывается при проверке прозрачности элемента формы.
Суть в том, что это невозможно сделать без использования ошибок пользовательского интерфейса, которые могут существовать, а могут и не существовать в Windows 11. Такое решение, скорее всего, в какой-то момент выйдет из строя, и, возможно, это уже произошло, поскольку «трюк» Color.Red
, похоже, не работает.
Единственное решение — создать вторую форму, которая использует почти нулевое значение непрозрачности, которая для всех практических целей будет выглядеть прозрачной, но позволит этой форме получать события мыши, которые затем можно будет передать в форму с прозрачными элементами.
Лично я надеялся избежать клуджа, но это кажется единственным выходом.
Это Windows Forms, WPF, MAUI или какая-то другая технология?