Hej! Denna posten blev lång men jag ville förklara allt så inget är oklart ifall någon orkar hjälpa mig. Eg säkert inte så svårt, men kommer inte riktigt loss... =) Jag har ett förslag: Testa att köra med dubbelbuffring, på så sätt tror jag inte att gdi kommer behöva anropas i lika stor utsträckning. Dubbelbuffring är en välkänd teknik, kolla lite på nätet så hittar du kodexempel och förklaringar. Hej! Hmm, efter en snabb analys av koden så får jag en känsla av att du uppdaterar din picturebox onödigt ofta. Hej!C# DirectX : Rita cirklar på en PictureBox, uppdatera snabbt = slött? DirectX ka
Jag råkade halka in på grafisk programmering i C# nyligen och stötte på patrull. Låt mig förklara vad det är för ett program jag ska göra:
Jag ska i princip läsa in en bild (en karta) med lite vägar och sådant. På denna karta ska ett antal noder (bilar) placeras och sedan ska dessa bilar (i form av blåa cirklar) röra sig längs vägarna. Min uppgift är inte att programmera AI eller så. Jag har en XML-fil med positionerna för varje bil vid varje given tidpunkt. Alltså, en lista med "events" där det för varje event och bil finns information om aktuell position för den bilen, x och y-koordinater på bilden (kartan).
So far so good. Det ser väl bra ut, de rör sig smidigt. Jag har skrivit det första med GDI+ (tror jag iaf), vanlig C#-programmering med andra ord.
PROBLEMET är att jag har en slider där jag ställer in hastigheten på animationen. Fram till en viss gräns ökar bilarna/noderna/cirklarna sin uppdateringshastighet men efter en viss punkt verkar det inte spela någon roll. Efter lite undersökningar verkar det som om min tråd, som uppdaterarar min PictureBox blir upptagen med just denna uppdatering (av PictureBox:en) lite för länge vilket gör att det finns en övre gräns på hur snabbt bilarna rör sig.
Så då kom jag in på DirectX. Jag kan inte speciell tmycket om det ännu, läser lite och letar information men jag behöver hjälp.
** hur ändrar jag i min PictureBox så att den gör samma sak som nu, men i DirectX? **
Nedan visar jag hur koden ser ut i nuvarande lösningen.
Först är det min UpdaterThread (2 metoder). Run-metoden loop:ar genom alla mina events dvs går igenom alla händelser då noderna ska ändra position och PictureBox:en ska ritas om.
<code>
// Class UpdaterThread
public void run()
{
int sleep;
temp1 = "";
while (true)
{
while (currentEvent < GlobalVariables.eventTimeTable.Rows.Count)
{
update(); // kallar metoden nedan.
currentEvent++;
sleep = (int)Math.Round((double)(1000 / speed), 0);
Thread.Sleep(sleep);
}
hasEnded = true;
animationControl.showCurrentEventId(currentEvent-1);
Console.WriteLine(temp1);
theThread.Suspend();
}
} // end run
// Hämtar ny pos., uppdaterar Node:en som finns sparade i en Hashtable. Se nedan.
private void update()
{
long time = long.Parse(GlobalVariables.eventTimeTable.Rows[currentEvent]["TIME"].ToString());
DataRow[] rows = GlobalVariables.eventTable.Select("EVENT_TYPE='1' AND TIME='" + time.ToString() + "'");
for (int i = 0; i < rows.Length; i++)
{
int temp = Convert.ToInt32(rows[i]["NODE_ID"]);
Node node = (Node)GlobalVariables.nodeTable[temp]; // hämtar nod
float x = float.Parse(rows[i]["NEW_POSITION_X"].ToString().Replace(Char.Parse("."), ','));
float y = float.Parse(rows[i]["NEW_POSITION_Y"].ToString().Replace(Char.Parse("."), ','));
float positionX = x;//(x - GlobalVariables.bottomLeftMetricX);
float positionY = y;//(y - GlobalVariables.bottomLeftMetricY);
float nbrOfPixelsX = positionX * GlobalVariables.pixelsPerMeterX;
float nbrOfPixelsY = positionY * GlobalVariables.pixelsPerMeterY;
node.updatePosition(nbrOfPixelsX, nbrOfPixelsY); // uppdatera pos
}
GlobalVariables.myPictureBox1.update(); // kallar en metod för att uppdatera PictureBox:en.
}
</code>
Som man kan se här är det inget konstigt. Jag har mätt lite tider (DateTime.Now.MilliSeconds) och kommeit fram till att det är just
GlobalVariables.myPictureBox1.update();
som tar tiden.
Min PictureBox:
<code>
// class MyPictureBox
using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
namespace STRAW_Visualizer
{
public partial class MyPictureBox : System.Windows.Forms.PictureBox
{
private Hashtable nodeTable;
public void setTable(Hashtable table)
{
this.nodeTable = table;
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics dc = e.Graphics;
base.OnPaint(e);
if (nodeTable != null)
{
IDictionaryEnumerator en = nodeTable.GetEnumerator();
//Console.WriteLine("a. " + System.DateTime.Now.Second + "." + System.DateTime.Now.Millisecond);
while (en.MoveNext())
{
Node temp = (Node)en.Value;
temp.Draw(dc); // Säger åt en Nod att rita om sig
}
//Console.WriteLine("b. " + System.DateTime.Now.Second + "." + System.DateTime.Now.Millisecond);
//Invalidate();
}
}
}
}
</code>
och sist min Node-class:
<code>
// Class Node
...
public void Draw(Graphics dc)
{
dc.DrawEllipse(pen, currentX - 8, currentY - 8, 16, 16);
Font drawFont = new Font("Arial", 9);
SolidBrush drawBrush = new SolidBrush(Color.Black);
dc.DrawString(nodeId.ToString(), drawFont, drawBrush, new PointF(currentX - 6, currentY - 6));
}
</code>
Jag behöver göra om min MyPictureBox till en DirectX-grej... men Draw-metoden finns inte kvar? Hur säger jag åt en sådan DirectX-picturebox att rita om sig?
Tack!Sv: C# DirectX : Rita cirklar på en PictureBox, uppdatera snabbt = slött? Direct
Sv:C# DirectX : Rita cirklar på en PictureBox, uppdatera snabbt = slött? Direct
Jo, dubbel buffring har jag redan dessvärre =(Sv: C# DirectX : Rita cirklar på en PictureBox, uppdatera snabbt = slött? Direct
Uppdatera alla positioner på bilarna, och sedan ritar du ut allihopa samtidigt, eller är det så du redan gör?
Mvh
Johan LindforsSv:C# DirectX : Rita cirklar på en PictureBox, uppdatera snabbt = slött? Direct
Jo, jag går igenom listan av alla bilar/noder och sedan gör jag en Invalidate eller vad det nu var.
Så det ritas bara om 1 gång...