弄了一个自定义控件,主要是两个TableLayoutPanel,一个作为表头使用,一个作为列表。要求垂直滚动条滚动时表头不动(这也是为什么用两个TableLayoutPanel的原因),水平滚动时,两个TableLayoutPanel一起滚动。
为此添加了一个VScrollBar和一个HScrollBar。但是不知道如何控制两个TableLayoutPlanel。如果单纯改变控件的loacation,界面闪烁的很厉害(控件比较多)。请问有什么办法吗?最好能有实例学习一下,谢谢。

解决方案 »

  1.   

    下面的代码示例向 PictureBox 控件添加水平和垂直滚动条,并将一个 Image 加载到该控件的 DoubleClick 事件的图片框中。您可在任何时候双击该图片框并加载新图像。如果图像比控件大,则将显示滚动条,以便您可以滚动查看图像的剩余部分。该示例假定已在 Form 上创建了一个 PictureBox(其两边分别停靠有 VScrollBar 和 HScrollBar)。它还假定已添加对 System.Drawing 命名空间的引用。请确保将 HandleScroll 方法同时设置为 VScrollBar 和 HScrollBar 的 Scroll 事件处理程序委托。有关可扩展此示例的其他代码,请参见 LargeChange、SmallChange、Maximum、Minimum 或 Value 成员。您可考虑基于滚动条的父控件的属性来设置滚动条的属性。例如,您可向该示例添加一种方法,将 Maximum 值设置为等于分配给 PictureBox 的 Image 的 Height 或 Width。将 LargeChange 值设置为等于 PictureBox 的高度或宽度(减去滚动条的高度或宽度)。这可防止用户滚动出图像的边缘,并且 LargeChange 值将只使图像的可查看区域移动与图片框中的显示区域相同的距离。using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    namespace Scrollbar
    {
        public class Form1 :  Form
       {
          private  OpenFileDialog openFileDialog1;
          private  PictureBox pictureBox1;
          private  VScrollBar vScrollBar1;
          private  HScrollBar hScrollBar1;
        
          public Form1()
          {
             InitializeComponent();
          }
        
          private void InitializeComponent()
          {
             this.openFileDialog1 = new OpenFileDialog();
             this.pictureBox1 = new PictureBox();
             this.vScrollBar1 = new VScrollBar();
             this.hScrollBar1 = new HScrollBar();
             this.pictureBox1.SuspendLayout();
             this.SuspendLayout();
            
             this.pictureBox1.BorderStyle = BorderStyle.FixedSingle;
             this.pictureBox1.Controls.AddRange(
                 new Control[] { this.vScrollBar1, this.hScrollBar1});
             this.pictureBox1.Dock = DockStyle.Fill;
             this.pictureBox1.Size = new System.Drawing.Size(440, 349);
             this.pictureBox1.DoubleClick += new EventHandler(this.pictureBox1_DoubleClick);         this.vScrollBar1.Dock = DockStyle.Right;
             this.vScrollBar1.Location = new System.Drawing.Point(422, 0);
             this.vScrollBar1.Size = new System.Drawing.Size(16, 331);
             this.vScrollBar1.Visible = false;
             this.vScrollBar1.Scroll += 
                 new ScrollEventHandler(this.HandleScroll);
             
             this.hScrollBar1.Dock = DockStyle.Bottom;
             this.hScrollBar1.Location = new System.Drawing.Point(0, 331);
             this.hScrollBar1.Size = new System.Drawing.Size(438, 16);
             this.hScrollBar1.Visible = false;
             this.hScrollBar1.Scroll += 
                 new ScrollEventHandler(this.HandleScroll);
             
             this.ClientSize = new System.Drawing.Size(440, 349);
             this.Controls.AddRange(new Control[] {this.pictureBox1});
             this.Text = "Form1";
             this.Resize += new System.EventHandler(this.Form1_Resize);
             this.pictureBox1.ResumeLayout(false);
             this.ResumeLayout(false);      }      [STAThread]
          static void Main() 
          {
             Application.Run(new Form1());
          }private void pictureBox1_DoubleClick (Object sender, EventArgs e)
    {
       // Open the dialog box so the user can select a new image.
       if(openFileDialog1.ShowDialog() != DialogResult.Cancel)
       {
          // Display the image in the PictureBox.
          pictureBox1.Image = Image.FromFile(openFileDialog1.FileName);
          this.DisplayScrollBars();
          this.SetScrollBarValues();
       }
    }
     
    private void Form1_Resize (Object sender, EventArgs e)
    {
       // If the PictureBox has an image, see if it needs 
       // scrollbars and refresh the image. 
       if(pictureBox1.Image != null)
       {
          this.DisplayScrollBars();
          this.SetScrollBarValues();
          this.Refresh();
       }
    }
     
    public void DisplayScrollBars()
    {
       // If the image is wider than the PictureBox, show the HScrollBar.
       if (pictureBox1.Width > pictureBox1.Image.Width - this.vScrollBar1.Width)
       {
          hScrollBar1.Visible = false;
       }
       else
       {
          hScrollBar1.Visible = true;
       }
     
       // If the image is taller than the PictureBox, show the VScrollBar.
       if (pictureBox1.Height > 
           pictureBox1.Image.Height - this.hScrollBar1.Height)
       {
          vScrollBar1.Visible = false;
       }
       else
       {
          vScrollBar1.Visible = true;
       }
    }
     
    private void HandleScroll(Object sender, ScrollEventArgs se)
    {
       /* Create a graphics object and draw a portion 
          of the image in the PictureBox. */
       Graphics g = pictureBox1.CreateGraphics();
       
       g.DrawImage(pictureBox1.Image, 
         new Rectangle(0, 0, pictureBox1.Right - vScrollBar1.Width, 
         pictureBox1.Bottom - hScrollBar1.Height), 
         new Rectangle(hScrollBar1.Value, vScrollBar1.Value, 
         pictureBox1.Right - vScrollBar1.Width,
         pictureBox1.Bottom - hScrollBar1.Height), 
         GraphicsUnit.Pixel);     pictureBox1.Update();
    }public void SetScrollBarValues() 
    {
       // Set the Maximum, Minimum, LargeChange and SmallChange properties.
       this.vScrollBar1.Minimum = 0;
       this.hScrollBar1.Minimum = 0;   // If the offset does not make the Maximum less than zero, set its value. 
       if( (this.pictureBox1.Image.Size.Width - pictureBox1.ClientSize.Width) > 0)
       {
          this.hScrollBar1.Maximum = 
              this.pictureBox1.Image.Size.Width - pictureBox1.ClientSize.Width;
       }
       // If the VScrollBar is visible, adjust the Maximum of the 
       // HSCrollBar to account for the width of the VScrollBar.  
       if(this.vScrollBar1.Visible)
       {
          this.hScrollBar1.Maximum += this.vScrollBar1.Width;
       }
       this.hScrollBar1.LargeChange = this.hScrollBar1.Maximum / 10;
       this.hScrollBar1.SmallChange = this.hScrollBar1.Maximum / 20;   // Adjust the Maximum value to make the raw Maximum value 
       // attainable by user interaction.
       this.hScrollBar1.Maximum += this.hScrollBar1.LargeChange;
         
       // If the offset does not make the Maximum less than zero, set its value.    
       if( (this.pictureBox1.Image.Size.Height - pictureBox1.ClientSize.Height) > 0)
       {
          this.vScrollBar1.Maximum = 
              this.pictureBox1.Image.Size.Height - pictureBox1.ClientSize.Height;
       }   // If the HScrollBar is visible, adjust the Maximum of the 
       // VSCrollBar to account for the width of the HScrollBar.
       if(this.hScrollBar1.Visible)
       {
          this.vScrollBar1.Maximum += this.hScrollBar1.Height;
       }
       this.vScrollBar1.LargeChange = this.vScrollBar1.Maximum / 10;
       this.vScrollBar1.SmallChange = this.vScrollBar1.Maximum / 20;
       
        // Adjust the Maximum value to make the raw Maximum value 
       // attainable by user interaction.
       this.vScrollBar1.Maximum += this.vScrollBar1.LargeChange;
       }  }
    }
      

  2.   

    MSDN里也是重画~~你改变loaction的思路是对的~~在VC里VScrollBar从来就是一个单独的控件,(例如:没有现成的richtextbox可以用),都是靠代码来实现的c#最不好的地方在于它让人们忘记了程序的根本!!让人以为所有的程序原本就是拖控件拖出来的
      

  3.   

    二楼的,我发帖之前也GOOGLE过,搜到的都是这个例子,但是我的控件不是自绘的,所以还是不太一样。我想是不是改变LOCATION也会导致控件重绘,所以闪烁的很厉害。顺便说一下TableLayoutPanel自带的滚动条滚动时,内容也无法同步滚动。这个是为什么呢?
      

  4.   


    this.SuspendLayout(); // 动前挂起布局
    ...
    this.ResumeLayout(true); 动完恢复布局
      

  5.   

    楼上的这个办法也用过了,没有用。
    后来经一位高人指点终于解决了这个问题,拿出来跟大家分享一下。这个办法一下解决了闪烁和同步滚动两个问题。其实过程挺简单的,原因不知道谁能解释一下。将要作为内容显示的TableLayOutPanel放入一个Panel,然后VScrollbar也放入这个Panel。然后Panel设为FILL,而TableLayOutPanel不能设为FIll(一旦Fill了肯定闪烁)。然后用VScrollbar操作TableLayOutPanel的滚动,就是LOCATION就能解决这两个问题。其实关键是TableLayOutPanel不能设为FILL,跟那个Panel没什么关系,这就需要我们根据内容计算出TableLayOutPanel的高度,并且还要考虑窗口最大化后TableLayOutPanel自动适应的问题。