[VC++ .NET] Rysowanie obiektu i przesuwanie nim myszką

0

Witam, mam taki problem, że potrzebuję zrobić moduł semi "architektoniczny". Pobieram z bazy danych wartości długość i szerokość - na podstawie tych wartości chciałbym aby moduł rysował obiekt - rysunek (wypełniony prostokąt), którym można by po kliknięciu myszki ruszać po planszy (planie budynku).

Każdy obiekt musiałby w takim razie obsługiwać handler na mousedown

Każdy obiekt musiałby być przesuwalny (czytanie współrzędnych kursora i podmiana wartości X,Y narysowanego prostokąta na współrzędne, tak że przy ruchu rysunek sam by się przerysowywał)..

Każdy obiekt musiałby być niezależny i "solidny"... tzn po narysowaniu dwóch czy trzech takich samych (kolejnych) obiektów nie mogły by się nakładać.

Każdy obiekt musiałby być usuwalny z planszy.

Domyślam się, że muszę zrobić własną klasę i każdy obiekt rysowany to obiekt tej klasy.. plus ten handler, ale teoria teoria a w praktyce nie mam zielonego pojęcia jak mam to zrobić..

Jeśli mogę prosić, to raczej o trochę kodu niż o odsyłanie do MSDN... byłem tam - nie pomogło. Może ktoś ma podobny przykład (lub inne podobne).. dzięki którym mógłbym zobaczyć jak to działa poprzez reverse engeneering?

0

Wydaje mi się, że najłatwiej stworzyć kontrolkę i po niej rysować.
Jeżeli rysunek jest 2d, to powiedzmy, że każdy element to pewien Rectangle. W takim wypadku należy sprawdzić, czy pozycja myszki zawiera się w tym Rectangle'u.
Wystarczy obsłużyć zdarzenia mouseMove/Up/Down.

0

To chyba nie przejdzie, bo zakładasz, że jest jeden z góry predefiniowany Rectangle na PictureBox.. owszem, mógłbym użyć ową kontrolkę, ale reszta pozostaje ta sama. Bowiem każdy prostokąt musi być generowany jako odrębny element jakiejś klasy.

1

Wroq miał na myśli (chyba...) żeby stworzyć kontrolkę jako planszę dla wszystkich obiektów. W niej trzymasz listę prostokątów, albo jeszcze lepiej - obiektów klasy Rysunek - i przy kliknięciu, poruszeniu myszą aktualizować dane.

0

Tak dokładnie... Stworzyć kontrolkę i nadpisać OnPaint. I tam wszystko rysować na podstawie Rectangle'ów albo obiektów własnej, stworzonej klasy. Przynajmniej mi się wydaje, że tak jest najprościej. :D

0

A poda któryś z was jakiś przykładowy kawałek kodu? Bo ja się najlepiej uczę analizując cudzy kod niż szukając po książkach.. <prosi>

0

Był taki gotowiec ze źródłami w samples'ach VC. Posiadał możliwość rysowania (generowania) kilku figur geometrycznych (rectangle, roundrectangle, elipse, polygone etc) z możliwością wskazywania na obiekty myszą i nie tylko 'ciąganie nimi po ekranie' ale także modyfikacją ich atrybutów (kolor, tło etc). Niestety kod jest w C++ (nie .Net). Jeśli jesteś zainteresowany mogę go poszukać.

0

Chętnie. Język jak język.. jak będę miał choć przykład to znajdę odpowiedniki w .net

0

W takim razie zadam jesza kilka pytań (jeśli można?). Program z samplesów opiera się na MFC (wcale nie taki trudny) ale bazuje na ScrollView - co oznacza że możesz mieć planszę większą niż ekran (automatyczna obsługa Scrollbarów) ale nie posiada zoom'a. Jeśli interesuje Cię (lub będzie potrzebny w przyszłości) zoom to może znajdę Ci raczej rozwiniętą przez siebie aplikację która już taki zoom posiada. Po drugie kod jest nie taki mały i może być zawiły (ma np obsługę Clipboard'u i podobnych bajerów). Napisz która opcja Cię interesuje.

1

Ja napisałem coś o co chyba chodzi w C# (dzisiaj już trzeci raz piszę coś dla kogoś, nie wiem co ze mną) ;)

Przykładowa aplikacja do przesuwania kolorowych prostokątów.

Wrzuciłem projekt (link)
Nowy plik, powinien zostać już na długo: Boxes.zip

Ale jak wiadomo pliki znikają a 4p pozostanie więc wrzucam główne źródła "ku pamięci"

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Box : UserControl
    {
        List<BoxItem> items;
        bool moving;
        BoxItem current;       // <- pamiętaj że obiekty są przekazywane przez referencję
        Point lastPos;

        public Box()
        {
            InitializeComponent();

            moving = false;
            items = new List<BoxItem>();
        }

        public BoxItem this[int ndx]
        {
            get { return items[ndx]; }
            set { items[ndx] = value; }
        }

        public void Add(BoxItem i)
        {
            this.items.Add(i);
            Invalidate(i.Position); // Wymuszamy ponowne narysowanie fragmentu kontrolki gdzie
                                    // boxItem się pojawia. Gdyby nie to, boxItem mógłby być
                                    // niewidoczny.
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            foreach (BoxItem i in items)
                e.Graphics.FillRectangle(new SolidBrush(i.Color), i.Position);
            base.OnPaint(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (!moving) return;
            
            Point currPos = e.Location;
            Point deltaPos = new Point(lastPos.X - currPos.X, lastPos.Y - currPos.Y);
            current.Position = new Rectangle(
                current.Position.X - deltaPos.X,
                current.Position.Y - deltaPos.Y,
                current.Position.Width,
                current.Position.Height);

            lastPos = currPos;

            Invalidate(); // Można to __bardzo__ przyśpieszyć dając jedynie zmieniony prostokąt
                          // do narysowania.

            base.OnMouseMove(e);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            foreach (BoxItem i in items)
            {
                if (i.Position.Contains(e.Location))
                {
                    current = i;
                    moving = true;
                    lastPos = e.Location;
                    break;
                }
            }

            base.OnMouseDown(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            moving = false;
            base.OnMouseUp(e);
        }
    }
}
using System.Drawing;

namespace WindowsFormsApplication1
{
    public class BoxItem
    {
        public BoxItem(Color color, Rectangle position)
        {
            this.Color = color;
            this.Position = position;
        }

        public Color Color
        { get; set; }

        public Rectangle Position
        { get; set; }
    }
}

Update 8.2.2012 - jako że okazało się że dalej ktoś czasami wpada na ten kod, wysłałem małą poprawkę (związaną z dynamicznym dodawaniem obiektów do kontrolki - chodzi o Invalidate() w Add() ) i zrobiłem ponowny upload projektu.

0
MSM napisał(a)

Ja napisałem coś o co chyba chodzi w C# (dzisiaj już trzeci raz piszę coś dla kogoś, nie wiem co ze mną) ;)

A czego Ci potrzeba ? :-D

1

jej, dzięki :) Popracuję nad tym kodem i spróbuję go przerobić do C++ .. nie wiem czy tu się daje jakieś Thanksy? Ale jestem bardzo dźwięczny :)

Udało się, w końcu naprawiłem i działa w 100% :) dziękuję jeszcze raz za okazaną pomoc.

0

MSM, jak odpalić Twój kod?

Application.Run(new Box()); 

wywala błąd - Argument 1: cannot convert from 'WindowsFormsApplication1.Box' to 'System.Windows.Forms.ApplicationContext'

1

Box to kontrolka, musisz albo dodać ją przez designera (przeciągnąć na okno - tylko do tego musisz ją załadować wcześniej) albo ręcznie dodać w kodzie, np. w Form1() { components.Add(new Box()); };

0

Dzięki wielkie, bardzo mi się to przyda.

1 użytkowników online, w tym zalogowanych: 0, gości: 1