C#: atestat și pregătire ONTI

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.

Î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.

Schemă pentru lecția 20: Figură 0: în spate; Figură 1: deasupra; Click (120, 100); Selecție: figura 1.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

Bazele C#

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.

Exersează cu o problemă →