C#中关于PANEL控件的Graphics绘图

作者&投稿:展厚 (若有异议请与网页底部的电邮联系)
c#中在一个Panel里画图 怎样能让前面画的图~

Graphics dc = panel1.CreateGraphics();//选择在哪个panel里面添加图画
//你想在不同的panel里面画图,把
//panel1改 panel2 ,panel3,panel4
// 就好了
Pen redpen = new Pen(Color.Red, 2);//定义画笔
dc.DrawRectangle(redpen,x,y,w,h);//画长方形,然后是坐标和长度

你是用窗体的load事件画图吧?试试下面的代码:
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
SolidBrush m = new SolidBrush(Color.Red);
g.FillEllipse(m, new Rectangle(0, 0, 100, 100));
}
窗体重绘时,引发Paint事件,应该在Paint事件中画图,窗体改动和重启仍然有图形。如果放在Load事件中,绘图后随着窗体启动消失了。

LZ关键问题是没有注意到图形在某位“位置”绘制后,如果该位置发生的移动,或其他图形遮挡了后会出现什么,如下图:

用其他什么东西,例如QQ遮挡 了一下原图形就没有了...因为在此之后没有人重新绘制了该图形,基于类似原因,即便你使用了Scoll,也无法看到后面的图形


你的程序我改造了一下,可以根据需求绘制图形,去掉Panel自带的HorizontalScroll,新增了一个hScrollBar(HorizontalScroll没有尝试成功,所以替换了,LZ可以多尝试下)

 private struct ImageContainerType
        {
            public Rectangle theImage;     // 图形容器--矩形
            public SolidBrush theBrush;    // 绘制该图形所用的画笔
        };
        // 绘制的图形的"容器"--这里用来存放绘制的矩形
        
        List<ImageContainerType> imageList;

        // 用于控制绘图位置的全局变量
        int indexDraw = 0;

        private void button1_Click(object sender, EventArgs e)
        {
            /*
                调整思路
             * 方案A:静态绘图
             * 1、将所有绘制的图形保存到imageList容器中
             * 2、在需要时再执行绘制,例如拖动Scoll时触发
             * 缺点:如果绘制的图形较多,将消耗大量内存
             * 优点:只需要执行一次图形创建过程,以后随时可以使用,节省CPU或GPU资源
             *      且算法简单
             * 
             * 方案B:动态绘图
             * 1、先绘制当前所需要的图形(在可见区间内)
             * 2、在需要时如Scoll,重新(在可见区间内)绘制所需要的图形
             */
            int[] nums = new int[10000];

            // 初始化图形容器
            imageList = new List<ImageContainerType>(100);
            ImageContainerType tempImage;

            Random random = new Random(); //随机数值
            for (int i = 0; i < 100; i++)
            {
                nums[i] = random.Next(0, 2);

            }
            for (int i = 0; i < 100; i++)
            {
                if (nums[i] == 1)
                {
                    SolidBrush r1 = new SolidBrush(Color.Red);//定义单色画刷    
                    Rectangle rect = new Rectangle(20 * i, 0, 10, 50);
                    //grap.FillRectangle(r1, rect);//填充这个矩形 
                    // 将当前图形存入容器
                    tempImage = new ImageContainerType();
                    tempImage.theBrush = new SolidBrush(Color.Red);
                    tempImage.theImage = new Rectangle(20 * i, 0, 10, 50);
                    imageList.Add(tempImage);
                }
                else
                {
                    SolidBrush b1 = new SolidBrush(Color.Blue);//定义单色画刷
                    Rectangle rect = new Rectangle(20 * i, 0, 10, 50);
                    //grap.FillRectangle(b1, rect);//填充这个矩形
                    tempImage = new ImageContainerType();
                    tempImage.theBrush = new SolidBrush(Color.Blue);
                    tempImage.theImage = new Rectangle(20 * i, 0, 10, 50);
                    imageList.Add(tempImage);
                }             
            }

            // [关键]设置Scorll的新值
            this.hScrollBar1.Maximum = 100;

            // 绘制全部图形
            DrawImage(0, imageList.Count - 1);

            MessageBox.Show("绘制完成");
        }
        /// <summary>
        /// 实际的图形绘制方法
        /// </summary>
        /// <param name="start">所需绘制图形的起始编号</param>
        /// <param name="end">所需绘制图形的结束编号,如果end在start则绘制所有剩下图形</param>
        void DrawImage(int start, int end)
        { 
            // 1、判定绘图容器是否存在
            if (imageList == null || imageList.Count <= 0)
            {
                MessageBox.Show("还没有生成图形");
                return;
            }

            // 2、绘图区间判定
            if (start >= imageList.Count || end >= imageList.Count)
            {
                MessageBox.Show("不在有效绘图区间");
                return;
            }

            // 3、
            if (start <= end)
            { 
                // 绘制从起始位置,到结束位置所有图形
                end = imageList.Count - 1;
            }

            // 4、绘制图形
            Graphics grap = pChart.CreateGraphics();
            grap.Clear(Color.White);
            Pen blue = new Pen(Color.Blue);
            Pen red = new Pen(Color.Red);
            for(int index=start;index<= end;index++)
            {
                grap.FillRectangle(imageList[index].theBrush, imageList[index].theImage);
            }            
        }

        /// <summary>
        /// 在Scroll实际中重绘Panel内容
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            // 每次重绘"当前位置"直至结尾的所有图形
            DrawImage(e.NewValue, imageList.Count - 1);
        }

得到的效果是:

你可以看到,Scoll正确发挥了作用,但貌似图形不正确阿....前面的没有了?

原因在于现有的重绘访法是

// 每次重绘"当前位置"直至结尾的所有图形
DrawImage(e.NewValue, imageList.Count - 1);

而在imageList容器中存放的图形其坐标已经固定了,因此绘制结果也就可以预期了——这距离使用Scoll拖动图形距离不远了:>


其实关键就是图形和界面之间相对位置的处理了——界面是静止的,那么只有让图动起来,看我的改造:

注意上面两个图形的坐标,0-99和9~99,然后看相应的图形。的确界面没动,但图形动了,看起来就像是Panel向右滑动了10个单位一样。修改Scoll事件中的绘图方法就可以达到所需要的效果了

        /// <summary>
        /// 在Scroll实际中重绘Panel内容
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            int theValue = e.NewValue;
            int theNewImageX_Index = 0;


            // 要想实现“动态效果”的关键是重新计算图形与“静止”的界面
            // 之间的相对位置,即“界面不动”图形动(我不动那就麻烦你动一下了:>)
            // 这将消耗一定的CPU资源
            // --尝试将图形的位置根据当前"位置"进行移动
            // --将当前图形设定为"相对于界面"的第一个图形,后面的图形依次+1
            for (int index = theValue; index < imageList.Count; index++)
            {
                ImageContainerType temp = new ImageContainerType();
                temp.theImage = new Rectangle(20 * theNewImageX_Index, 0, 10, 50);
                temp.theBrush = imageList[index].theBrush;
                imageList[index] = temp;

                theNewImageX_Index++;
            }

            // 然后重新绘制图形
            DrawImage(theValue, imageList.Count - 1);
        }

 这里最关键的就是重新计算图形的坐标

new Rectangle(20 * theNewImageX_Index, 0, 10, 50);


private void panel1_Paint(object sender, PaintEventArgs e) { DrawMe(e.Graphics); }private void DrawMe(Graphics g){g.FillRectangle(blueBrush, x, y, width, height);...这里绘制 主意:绘制结束后不要使用 g.Dispone() 因为这个g来自控件绘制本身 不能销毁 }


平武县15546133705: C#中的panel控件具体是干什么的? -
稻红可尼: panel 就是一个容器 就像FORM一样的(可以看着顶层容器) PANEL主要用于方便程序人员 选择显示的内容 FORM里面放好多PANEL PANEL里面放好多控件类的东西 你只要选择PANEL就可以控制显示····

平武县15546133705: C# 窗体应用程序中的Panel控件有什么作用,怎么使用啊?
稻红可尼: 是一个容器,里面可以放控件有一种常用的方法就是当你要改变窗体里面的内容时又不想重新打开另一个窗口,你就可以用两个panel放不同的控件,当窗口加载时显示一个,隐藏另一个,当你需要做什么操作时就可以把当前的隐藏再把另一个显示就行了,那样子数据交换也不用那么麻烦

平武县15546133705: C#panel控件问题 -
稻红可尼: 1.为什么Button会显示在图片下面?这跟你把pictureBox Button 加入panel的顺序有关系~你先加入Button 然后在加入pictureBox ,则pictureBox在 Button 上面,反之相反2.如何让他显示在pictureBox上面?鼠标在Button 上点右键,选择【置于顶层】...

平武县15546133705: 在c#中,panel主要用来当做控件的容器来使用? -
稻红可尼: 是的 可以放一组单选框,使用的时候只能选定一个 也可以放一组复选框 也可以放其他的控件 放其他控件时只是把控件分组了而已

平武县15546133705: .NET(C#)环境下,如何在panel容器里自由拖动picturebox控件 -
稻红可尼: 思路是这样的.得有三个变量. 记录x坐标: int xPos; 记录y坐标: int yPos; 记录是否按下鼠标: bool MoveFlag;//在picturebox的鼠标按下事件里,记录三个变量. private void picBox_MouseDown(object sender, MouseEventArgs e) {...

平武县15546133705: C#中向FlowLayoutPanel中添加控件使控件之间间隔为0,那个该怎么做? -
稻红可尼: picture.Click += new EventHandler(pc);void pc(object sender, EventArgs e) { //..... }

平武县15546133705: C# 获取Panel中的子控件属性 -
稻红可尼: 1.你知道它的name,panel1.Controls["textbox1"] 返回的是Control类型,你自己(TextBox)一下2.你知道它的索引值(index),panel1.Controls[0] 返回类型同上3.你知道它的类型TextBox,好了.你慢慢的foreach controls属性吧.如果你的控件被再次套了一层.那你就得慢慢找了.一层一层的来

平武县15546133705: 在C#中,如果我将一个panel控件的GenerateMember属性设置为false的时候,在timer控件里无法调用? -
稻红可尼: GenerateMember设置为false表示它不会是当前对象的一个成员变量,而只是在初始化的时候生成而已,也就是说在你的timer控件事件里是没有办法调用的,因为你调用的时候默认使用的是this.一般来说,我们不把GenerateMember设置为false,基本都是true;

平武县15546133705: c#里面如图所示的界面是什么控件做的? -
稻红可尼: 底版就是一Panel,上面再加上Button,每个Button再对应一Panel,用代码实现点击隐藏,可以自己写,网上也有做好的这种控件

平武县15546133705: C#在form窗体的panel控件中添加一个label控件,怎么能让panel的text文本一直在panel的中间?
稻红可尼: 我来告诉你标准答案!注册Panel的Resize事件,里面写下这些代码: label.Location=newPoint(Convert.ToInt32(panel.Width-label.Width)/2, Convert.ToInt32(panel.Height-label.Height)/2); 也就是计算label相对于panel的中心位置,赋给Location属性即可.

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网