为了实现这种类型的交互式艺术品,您可以在其中拖动框并在它们之间绘制连接线,我正在使用下面的代码。
基本上,当鼠标被拖动(移动框)或通过单击新框在面板上进行新选择时,我清除面板,绘制所有矩形,所有文本,然后使用计时器绘制所有线连接(大约每秒 20 次)。然而,重新绘制面板组件似乎很慢,并且会产生非常烦人的闪烁效果。有没有办法优化这段代码?/ 让绘图更有效率?
public MainForm()
{
// Create surface and pen to use for all drawing
surface = NodesPanel.CreateGraphics();
surface.InterpolationMode = InterpolationMode.Default;
surface.SmoothingMode = SmoothingMode.Default;
penl = new Pen(Color.Blue, 2.0f);
....
timer.Tick += new EventHandler(timer_Tick);
timer.Interval = 60; // Timer call
timer.Enabled = true; // Enable the timer
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
if (refreshScreen) // when dragging a box of making a new selection
{
RenderScreen();
}
}
public void RenderScreen()
{
surface.Clear(Color.White);
drawUnselectedNodes();
if (showSearchGate)
{
drawGates();
}
if (currentlyClickedNode != null && !(currentlyClickedNode is Gate))
{
currentlyClickedNode.drawMyConnections(surface, penl); // Draw in a different colour
currentlyClickedNode.drawMe(surface, penl);
if (drawingLine)
{
DrawingHelper.DrawLine(surface, penl, currentlyClickedNode.getGatePosition(), linePosition, "regular");
}
}
}
private void drawUnselectedNodes()
{
foreach (QuestNode q in nodes)
{
if (q != currentlyClickedNode)
{
q.drawMe(surface, penl);
}
}
}
// The node structure
public class QuestNode
{
...
public void drawMe(Graphics g, Pen p)
{
DrawingHelper.DrawRoundRectWithText
(g, p, pos.x, pos.y, NODE_WIDTH * currentScale, NODE_HEIGHT *
currentScale, GATE_RADIUS * currentScale, name, description, true,
(selected ? RECTANGLE_SELECTED_COLOR : ANGLE_UNSELECTED_COLOR));
}
public void drawMyConnections(Graphics g, Pen p)
{
foreach (QuestNode qn in relatedQuests)
{
DrawingHelper.DrawLine(g, p, pos, qn.getGatePosition(), "regular");
}
}
}
static class DrawingHelper
{
public static SolidBrush STANDARD_BRUSH = new SolidBrush(RECTANGLE_COLOR);
public static int PRIMARY_TEXT_FONT_SIZE = 10;
public static Font PRIMARY_FONT_STYLE = new Font("Arial", PRIMARY_TEXT_FONT_SIZE);
public static int SECONDARY_TEXT_FONT_SIZE = 8;
public static Font SECONDARY_FONT_STYLE = new Font("Arial", SECONDARY_TEXT_FONT_SIZE);
public static void DrawRoundRectWithText(Graphics g, Pen p, float x, float y,
float width, float height, float gateRadius, string textFirstLike,
string textSecondsLine, bool hasGate, Color color)
{
Graphics formGraphics = g;
g.InterpolationMode = InterpolationMode.Default;
g.SmoothingMode = SmoothingMode.Default;
SolidBrush myBrush = STANDARD_BRUSH;
myBrush.Color = color;
p.DashPattern = new float[] { 1 };
Rectangle rect = new Rectangle((int)x, (int)y, (int)width, (int)height);
p.Width = RECTANGLE_BORDER;
formGraphics.FillRectangle(myBrush, rect);
p.Color = RECTANGLE_COLOR;
formGraphics.DrawRectangle(p, rect);
DrawString(g, textFirstLike, x + TEXT_OFFSET_X, y + height / 4, PRIMARY_TEXT_FONT_SIZE, (int)width);
DrawString(g, textSecondsLine, x + TEXT_OFFSET_X, y + height / 2, SECONDARY_TEXT_FONT_SIZE, (int)width);
int gateWidth = (int)gateRadius;
int gateHeight = (int)gateRadius;
if (hasGate)
{
myBrush.Color = GATE_COLOR;
Rectangle circle = new Rectangle((int)(x + width) - gateWidth/2, (int)(y + height) - gateHeight/2, gateWidth, gateHeight);
formGraphics.FillEllipse(myBrush, circle);
formGraphics.DrawEllipse(p, circle);
}
Point[] diamondPoints = new Point[4];
diamondPoints[0] = new Point((int)(x - gateWidth / 2), (int)y);
diamondPoints[1] = new Point((int)x, (int)(y - gateHeight / 2));
diamondPoints[2] = new Point((int)(x + gateWidth / 2), (int)y);
diamondPoints[3] = new Point((int)x, (int)(y + gateHeight / 2));
myBrush.Color = Color.LightGray;
formGraphics.FillPolygon(myBrush, diamondPoints);
formGraphics.DrawPolygon(p, diamondPoints);
}
}
public static void DrawLine(Graphics g, Pen p, Vector2D origin, Vector2D end, string style)
{
Pen myPen = p;
p.Color = Color.Black;
Graphics formGraphics = g;
g.InterpolationMode = InterpolationMode.Default;
g.SmoothingMode = SmoothingMode.Default;
myPen.Width = LINE_BORDER;
if (style == "dotted")
{
myPen.DashPattern = new float[] { 1, 1, 0.5f };
}
formGraphics.DrawLine(myPen, origin.x, origin.y, end.x, end.y);
}
private static void DrawString(Graphics g, string text, float posX, float posY, int fontSize, int stringMaxWidth)
{
string drawString = text;
Font drawFont = (fontSize == PRIMARY_TEXT_FONT_SIZE) ? PRIMARY_FONT_STYLE : SECONDARY_FONT_STYLE;
SolidBrush drawBrush = STANDARD_BRUSH;
drawBrush.Color = Color.Black;
float x = posX;
float y = posY;
float charHeight = drawFont.GetHeight() / 2;
int maxChars = (int)(stringMaxWidth / charHeight);
if (drawString.Length > (maxChars - 3))
{
drawString = drawString.Substring(0, maxChars - 3) + "...";
}
g.DrawString(drawString, drawFont, drawBrush, x, y);
}