Piszę aplikację, w której jest możliwość rysowania grafów. Niby działa, jednak gdy jest dużo obiektów, tzn. wierzchołków i krawędzi to całość topornie się przerysowuje (np. podczas ich przesuwania). Jak temu zaradzić?
PS. doublebuffer nic nie pomaga.
najpierw napisz w czym rysujesz: urządzeniem graphics czy w Open GL? Pokaż też część kodu.
graphics + obiekty vb.powerpacks
private void RysujKrawedz(int krawedz, TextBox textB)
{
// Pobiera krawędź do rysowania oraz punkty łączące
Krawedz p = krawedzie[krawedz];
Wierzcholek from = wierzcholki[p.from];
Wierzcholek to = wierzcholki[p.to];
Point pFrom = new Point(from.owal.Location.X + size / 2, from.owal.Location.Y + size / 2);
Point pTo = new Point(to.owal.Location.X + size / 2, to.owal.Location.Y + size / 2);
Graphics g = panel1.CreateGraphics();
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
pen.StartCap = LineCap.Round;
pen.EndCap = LineCap.ArrowAnchor;
g.DrawLine(pen, PrzesunieciePunktu.nowyFrom(pFrom, pTo, size + 6),
PrzesunieciePunktu.nowyTo(pFrom, pTo, size + 6));
textB.Name = krawedz.ToString();
textB.Size = new System.Drawing.Size(30, 20);
textB.Location = new System.Drawing.Point(((pFrom.X + pTo.X) / 2) - textB.Size.Width / 2,
((pFrom.Y + pTo.Y) / 2) - textB.Size.Height / 2);
textB.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
textB.TextAlign = HorizontalAlignment.Center;
textB.Leave += new EventHandler(textBoxWartosc_Leave);
textB.Parent = panel1;
g.Dispose();
}
private void dodajWierzcholek(int X, int Y, int S1, int S2)
{
OvalShape owal = new OvalShape();
wierzcholki.Add(new Wierzcholek(new Point(X, Y), numV, owal));
numV += 1;
wierzcholki[wierzcholki.Count - 1].owal.Location = new Point(X - size/2, Y- size/2);
wierzcholki[wierzcholki.Count - 1].owal.Size = new Size(S1, S2);
wierzcholki[wierzcholki.Count - 1].owal.Parent = kontener;
wierzcholki[wierzcholki.Count - 1].owal.BorderColor = Color.Black;
wierzcholki[wierzcholki.Count - 1].owal.BackStyle = BackStyle.Transparent;
//wierzcholki[wierzcholki.Count - 1].owal.BackColor = Color.DodgerBlue;
wierzcholki[wierzcholki.Count - 1].owal.BorderWidth = 1;
int wieName = numV - 1;
wierzcholki[wierzcholki.Count - 1].owal.Name = wieName.ToString();
wierzcholki[wierzcholki.Count - 1].owal.Cursor = System.Windows.Forms.Cursors.Hand;
// zdarzenia myszy
wierzcholki[wierzcholki.Count - 1].owal.MouseDown += new MouseEventHandler(chwyt);
wierzcholki[wierzcholki.Count - 1].owal.MouseEnter += new EventHandler(wejscie);
wierzcholki[wierzcholki.Count - 1].owal.MouseLeave += new EventHandler(wyjscie);
wierzcholki[wierzcholki.Count - 1].owal.MouseClick += new MouseEventHandler(owal_MouseClick);
// menu kontekstowe
wierzcholki[wierzcholki.Count - 1].owal.ContextMenu = new ContextMenu();
wierzcholki[wierzcholki.Count - 1].owal.ContextMenu.MenuItems.Add("Usuń", new System.EventHandler(this.usunMenuItem_Click));
wierzcholki[wierzcholki.Count - 1].owal.ContextMenu.MenuItems.Add("Anuluj", new System.EventHandler(this.anulujMenuItem_Click));
}
oraz zdarzenia odpowiedzialne za przesuwanie wierzchołków
private void chwyt(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && radioButtonW.Checked)
{
ow = (OvalShape)sender;
Xpos = MousePosition.X;
Ypos = MousePosition.Y;
ow.MouseMove += new MouseEventHandler(przesuwam);
ow.MouseUp += new MouseEventHandler(puscilem);
}
}
private void przesuwam(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && radioButtonW.Checked)
{
OvalShape ow = (OvalShape)sender;
zmianaX = MousePosition.X - Xpos;
zmianaY = MousePosition.Y - Ypos;
foreach (int w in listaKr)
{
RysujKrawedz(w, krawedzie[w].textB);
}
ow.Location = new Point(ow.Location.X + zmianaX, ow.Location.Y + zmianaY);
Xpos = MousePosition.X;
Ypos = MousePosition.Y;
textBox1.Text = "Name: " + ow.Name + ", Pozycja: " + ow.Location + ", ilość krawędzi: " + listaKr.Count.ToString();
}
}
private void puscilem(object sender, MouseEventArgs e)
{
OvalShape ow = (OvalShape)sender;
if (e.Button == MouseButtons.Left && radioButtonW.Checked)
ow.MouseMove -= new MouseEventHandler(przesuwam);
}
Opisany przez Ciebie problem raczej jest spowodowany tym, że rysujesz cały graf prawdopodobnie zbyt często. Samo rysowanie powinieneś wykonywać tylko i wyłącznie w momencie zmiany grafu (jak dodanie/usunięcia wierzchołka czy krawędzi) zapisaniu Bitmapy do zmiennej i potem w momencie odrysowywania brać swój obraz grafu. Jeżeli rysujesz graf za każdym razem kiedy przemieszczasz okno/zmieniasz jego rozmiar to jest to bez sensu - jeżeli chcesz aby graf dopasowywał się wielkością do okna to zawsze możesz narysować bitmapę w skali 1:1 a potem ją zmniejszyć - możesz wtedy skorzystać z LockBit'a (http://msdn.microsoft.com/en-us/library/5ey6h79d.aspx) oraz BitmapData (http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.aspx) oraz jakiegoś algorytmu w celu zmniejszenia już samej zawartości bitmapy.
Poza tym widzę, że do każdego z obiektów jakim jest wierzchołek przypisujesz olbrzymią ilość klas czy zdarzeń. Spróbuj inaczej to rozwiązać. - Np. możesz trzymać wyłącznie współrzędne wierzchołków. Na obiekcie na którym rysujesz ów graf zrób swoje zdarzenia (np. ruch myszki) i sprawdzaj czy znajdujesz się na którymś z punktów (ew. obok niego) i tak samo zrób sprawdzanie po kliknięciu prawym przyciskiem myszy czy jesteś w jakimś wierzchołku i jeżeli jesteś to faktycznie wyświetl menu kontekstowe.
Ja bym jakoś tak próbował, acz nie daje gwarancji, że to na pewno zdałoby egzamin.
Dzięki za pomoc, sprawdzę to z bitmapami.
Wytłumaczę tylko jak działa to "przesuwanie obiektów":
Po najechaniu myszka na wierzchołek wywoływane jest zdarzenie
private void wejscie(object sender, EventArgs e)
{
OvalShape ow = (OvalShape)sender;
ow.BorderColor = Color.Red;
int numer = Int32.Parse(ow.Name);
foreach (Krawedz kr in krawedzie)
{
if (kr.from == numer || kr.to == numer)
listaKr.Add(Int32.Parse(kr.textB.Name));
}
}
tworzy listę krawędzi powiązanych z wierzchołkiem.
następnie samo przesuniecie wierzchołka powoduje jedynie zmianę położenia kształtu "owal" reprezentującego wierzchołek
ow.Location = new Point(ow.Location.X + zmianaX, ow.Location.Y + zmianaY);
oraz przerysowuje krawędzie na podstawie wcześniej wypełnionej listy foreach (int w in listaKr)
{
RysujKrawedz(w, krawedzie[w].textB);
}
wyjście kursora z wierzchołka czyści listę
```csharp
private void wyjscie(object sender, EventArgs e)
{
OvalShape ow = (OvalShape)sender;
ow.BorderColor = Color.Black;
listaKr.RemoveAll(delegate(int v)
{
return true;
});
}
Pytanie:
Czy po wprowadzeniu wcześniej proponowanych zmian, nadal będzie możliwość obsługi tych zdarzeń?
Zarejestruj się i dołącz do największej społeczności programistów w Polsce.
Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.