C#: selectarea figurilor prin coordonatele mouse-ului
Asociază clickurile dintr-un formular C# cu obiectele desenate. Folosește hit testing, o ordine explicită de selecție și coordonate în același sistem.
În acest material
Într-un editor simplu, un click trebuie să identifice obiectul desenat sub cursor. Această operație se numește hit testing. Pentru dreptunghiuri folosim Contains, iar pentru forme mai complexe am avea nevoie de un test geometric adecvat. Punctul clickului și figura trebuie descrise în același sistem de coordonate.
Cum lucrezi cu exemplul
Exemplul complet se compilează ca Windows Forms App pe .NET Framework 4.8, cu C# 7.3. Deschide Lesson.csproj din arhivă în Visual Studio pe Windows. Rulează scenariile descrise mai jos; verificarea compilării nu înlocuiește testarea ferestrei și a dispozitivelor folosite.
Descarcă sursele și instrucțiunile.
Ideea și pașii de implementare
Păstrăm două dreptunghiuri într-o listă și un index al selecției, inițial minus unu. Paint le desenează în ordinea listei. Ultimul desenat acoperă obiectele precedente, deci căutarea la click pornește de la sfârșit. La prima potrivire ne oprim, astfel încât selectăm figura vizibilă deasupra.
MouseEventArgs.Location conține coordonatele relative la controlul care a primit evenimentul. Dacă desenezi într-un Panel, evenimentul trebuie tratat în același Panel sau coordonatele trebuie convertite. În exemplu desenăm și tratăm clickul direct pe formular, fără conversie.
Exemplu și rezultat așteptat
Primul dreptunghi ocupă zona cu origine (30, 50) și mărime 140×100. Al doilea începe la (110, 90), având o zonă comună cu primul. Clickul la (120, 100) selectează al doilea, fiindcă acesta este desenat ultimul. Clickul în afara ambelor elimină selecția.
Figură 0: în spate → Figură 1: deasupra → Click (120, 100) → Selecție: figura 1.Mărește schema ↗
Codul complet
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new LessonForm());
}
}
class LessonForm : Form
{
readonly Rectangle[] shapes={new Rectangle(30,50,140,100),new Rectangle(110,90,150,100)};
int selected=-1;
public LessonForm() { Text="Selectare figuri"; ClientSize=new Size(360,260); DoubleBuffered=true; }
protected override void OnMouseDown(MouseEventArgs e) {
base.OnMouseDown(e); if(e.Button!=MouseButtons.Left) return;
selected=-1;
for(int i=shapes.Length-1;i>=0;i--) if(shapes[i].Contains(e.Location)) {selected=i;break;}
Invalidate();
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
for(int i=0;i<shapes.Length;i++) {
e.Graphics.FillRectangle(i==0 ? Brushes.LightBlue : Brushes.PaleGreen,shapes[i]);
using(var pen=new Pen(i==selected ? Color.Red : Color.Black,i==selected ? 3 : 1))
e.Graphics.DrawRectangle(pen,shapes[i]);
}
e.Graphics.DrawString("Selectat: " + selected,Font,Brushes.Black,20,215);
}
}
Greșeli și limite
Nu folosi coordonatele globale ale ecranului împreună cu dreptunghiuri locale. Nu selecta primul obiect găsit dacă ordinea vizuală cere obiectul de deasupra. Contains folosește convenția propriilor limite: punctele de pe marginea dreaptă sau de jos nu sunt tratate la fel ca interiorul. Precizează și testează această convenție.
Exersează
Verifică un punct numai în prima figură, unul numai în a doua, unul în suprapunere și unul exterior. Schimbă ordinea listei și observă că se schimbă și figura de deasupra. Adaugă deplasarea figurii selectate cu săgețile într-o lecție ulterioară, păstrând datele în model și solicitând redesenare.
Continuă parcursul
Parcursul complet de 50 de lecții
Lecția precedentă: C#: desene persistente cu Paint și Invalidate
Lecția următoare: C#: comenzi de tastatură și focalizare previzibilă.
Referință: documentația Microsoft.
Întrebări frecvente
De ce parcurg lista invers?
Pentru că ultimul obiect desenat apare deasupra și trebuie selectat primul în zona de suprapunere.
Ce coordonate are e.Location?
Coordonate relative la controlul care a primit evenimentul.
Cum elimin selecția?
Pui indexul la minus unu când niciun obiect nu conține punctul și redesenezi.
Un pas mai departe
Autentifică-te pentru a păstra progresul în cont.