【问题标题】:C# draw in panel and shift left the drawn objectsC#在面板中绘制并左移绘制的对象
【发布时间】:2023-03-18 02:00:01
【问题描述】:

我正在从左侧开始在面板中绘制矩形。

当我到达面板的右侧时,我想将之前绘制的矩形向左移动,以便有空间绘制另一个矩形,依此类推。

哪种方法最简单?

我正在使用 System.Drawings.Graphics 绘图。

我正在使用 Winforms。代码是:

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

namespace FFViewer
{
    public partial class Form1 : Form
    {
        [DllImport("shlwapi.dll")]
        public static extern int ColorHLSToRGB(int H, int L, int S);

        int x=0;
        int y=300;
        int h = 0;


        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            panel_Paint();

            x = x + 40;
            h = h + 40;

            if (h >= 240)
                h = 0;
        }

        private void panel_Paint()
        {
            int val;
            Color color;

            val = ColorHLSToRGB(h, 128, 240);

            Graphics g = panel1.CreateGraphics();

            color = ColorTranslator.FromWin32(val);

            SolidBrush sb = new SolidBrush( color );

            g.FillRectangle(sb, x, y, 40, 100);

        }
    }

}

所以,当我在右侧绘制最新的矩形时,我想将所有矩形向左移动以留出空间在右侧绘制另一个。

附:我没有足够的声誉来发布图片:(

【问题讨论】:

  • 你有没有尝试过?
  • 向我们展示您已经做过的事情,发布之前和之后的图片,指定正在使用的技术(例如:Winforms 或 WPF)...
  • 要么将它们绘制在不同的位置,要么绘制到位图中并移动位图

标签: c# winforms drawing


【解决方案1】:

这是“老派”的做法。这基本上是当需要显示实时值的连续图并且您不想在任何地方存储任何值时所做的。这有严重的限制,因为它从屏幕复制,并且当窗口重新绘制自身时,绘图将被删除。第一个示例仅用于演示该过程,并且是您创建初始块的方式的扩展:

public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
    }

    [DllImport("shlwapi.dll")]
    public static extern int ColorHLSToRGB(int H, int L, int S);

    int x = 0;
    int width = 40;
    int y = 300;
    int height = 100;
    int h = 0;

    private void button1_Click(object sender, EventArgs e)
    {
        if (x + width > panel1.ClientSize.Width) // if drawing the next block would exceed the panel width...
        {
            // capture what's currently on the screen
            Bitmap bmp = new Bitmap(x, height);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.CopyFromScreen(panel1.PointToScreen(new Point(0, y)), new Point(0, 0), bmp.Size);
            }
            // draw it shifted to the left
            using (Graphics g = panel1.CreateGraphics())
            {
                g.DrawImage(bmp, new Point(-width, y));
            }
            // move x back so the new rectangle will draw where the last one was previously
            x = x - width;                
        }

        // draw the new block and increment values
        panel_Paint();
        x = x + width;
        h = h + width;
        if (h >= 240)
        { 
            h = 0;
        }
    }

    private void panel_Paint()
    {
        int val;
        Color color;
        val = ColorHLSToRGB(h, 128, 240);
        color = ColorTranslator.FromWin32(val);

        using (Graphics g = panel1.CreateGraphics())
        {
            using (SolidBrush sb = new SolidBrush(color))
            {
                g.FillRectangle(sb, x, y, width, height);
            }
        }
    }

}

这可以通过创建正确大小的位图并绘制到该位图来解决。然后你移动所有东西并在右侧绘制新块。最后,您将在 Paint() 事件中绘制该位图。所以这和上面做的一样,除了我们不是从屏幕复制,面板会在请求时正确地重绘自己:

public partial class Form1 : Form
{

    [DllImport("shlwapi.dll")]
    public static extern int ColorHLSToRGB(int H, int L, int S);

    int x = 0;
    int width = 40;
    int y = 300;
    int height = 100;
    int h = 0;

    Bitmap bmp;

    public Form1()
    {
        InitializeComponent();
        this.Load += Form1_Load;
        panel1.Paint += Panel1_Paint;
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        int numBlocks = (int)(panel1.Width / width);
        bmp = new Bitmap(numBlocks * width, height);
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.Clear(panel1.BackColor);
        }
    }

    private void Panel1_Paint(object sender, PaintEventArgs e)
    {
        if (bmp != null)
        {
            e.Graphics.DrawImage(bmp, new Point(0, y));
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        using (Graphics g = Graphics.FromImage(bmp))
        {
            if (x + width > bmp.Width) // if drawing the next block would exceed the bmp width...
            {                
                g.DrawImage(bmp, new Point(-width, 0)); // draw ourself shifted to the left   
                x = x - width;
            }

            // draw the new block 
            int val;
            Color color;
            val = ColorHLSToRGB(h, 128, 240);
            color = ColorTranslator.FromWin32(val);
            using (SolidBrush sb = new SolidBrush(color))
            {
                g.FillRectangle(sb, x, 0, width, height);
            }
        }

        x = x + width;
        h = h + width;
        if (h >= 240)
        { 
            h = 0;
        }

        panel1.Invalidate(); // force panel1 to redraw itself
    }

}

【讨论】:

  • 感谢您的建议。
  • 最后我需要的是显示来自鱼探仪的数据,所以我是在实时值的连续图的情况下。每个条具有与不同深度的回波强度相关的不同颜色的部分。这种类型的图表可以用Chart控件来完成吗?
  • 我从来没有使用过图表控件,所以我不确定。您绝对可以将这种技术用于实时图表。不过,我会启用双缓冲。更新的频率如何?这确实是 WinForms 的决定因素,因为它不会提供非常高的帧速率。
  • 我正在使用您建议我的技术,并且效果很好。在最坏的情况下,每 300 毫秒更新一次。 ——
  • 所以大约每秒更新 3 次。如果您的输出区域的大小不是太大,它可能会表现得足够好,可以使用。
【解决方案2】:

您不应使用panel1.CreateGraphics(),而应处理面板的Paint 事件,否则矩形可能会消失,例如在您的表单前面出现一个弹出窗口后:

panel1.Paint += new PaintEventHandler(panel1_paint);

您需要在绘制处理程序中绘制所有(可见)矩形;您可以在表单中保留 List<Rectangle> 来存储您添加的矩形:

private List<Rectangle> rectangles = new List<Rectangle>();
...
private void button1_Click(object sender, EventArgs e)
{
    rectangles.Add(new Rectangle(x, y, width, height));
    panel1.Invalidate(); // cause the paint event to be called
    // todo increment x/y
}

然后,在panel1_Paint 处理程序中,您可以在调用Graphics.TranslateTransform() 移动整个绘图区域之后简单地绘制矩形:

private void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.TranslateTransform(-x, 0);
    foreach (Rectangle rectangle in rectangles)
    {
        // paint em
    }

    e.Graphics.ResetTransform();
}

【讨论】:

  • 感谢您的建议。
猜你喜欢
  • 2015-04-08
  • 1970-01-01
  • 2021-08-11
  • 1970-01-01
  • 2012-06-21
  • 2012-09-11
  • 1970-01-01
  • 1970-01-01
  • 2020-08-04
相关资源
最近更新 更多