2011-12-02 76 views
1

我想实现一个所有者绘制ListView,因为基本控制吃了我需要对齐列中的值的制表符。Listview问题ownerdraw模式文本呈现

MSDN为例,我能够接近。我还有的唯一问题是,当文本不适合列时,使用省略号的时间段比在默认文本呈现中的间隔更紧密;如果字体为粗体,那么句点一起运行为下划线。

下面的程序演示了这个问题。它有4个ListViews:顶部的两个是使用默认渲染绘制的。底部的两个是所有者,右边的一对是粗体的。出于篇幅的原因,我删除了所有我不需要的东西来演示问题,这就是为什么ownerdawn ListViews没有列标题。

查看放大的屏幕截图,所有者绘制的ListView中省略号的周期间隔一个像素;那些在默认图纸中有两个像素的间距。当粗体将周期扩展为两个像素时,所有者绘制的图像会合并为一个看起来像下划线的实体。

在文字渲染中还有其他细微差异;但省略号是唯一一个很容易看到而没有缩放的。然而,这些差异让我怀疑问题是一个更普遍的问题。 可能是GDI vs GDI +渲染?除了我认为只能在应用程序级别上有所不同。显然不是,切换Application.SetCompatibleTextRenderingDefault()不会影响任何内容。

using System; 
using System.Drawing; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 
{ 
    public class Form1 : Form 
    { 
     private void ListViewDrawSubItem(object sender, DrawListViewSubItemEventArgs e) 
     { 
      ListView listView = sender as ListView; 
      using (StringFormat sf = new StringFormat()) 
      { 
       // Draw the standard background. 
       e.DrawBackground(); 
       sf.SetTabStops(0, new float[] {12, 12, 12, 12, 12}); 
       sf.FormatFlags = sf.FormatFlags | StringFormatFlags.NoWrap; 
       sf.Trimming = StringTrimming.EllipsisCharacter; 

       // Draw the header text. 
       // passing the controls font directly causes an ArguementException); 
       using (Font headerFont = new Font(listView.Font.Name, listView.Font.Size, listView.Font.Style)) 
       { 
        e.Graphics.DrawString(e.SubItem.Text, headerFont, Brushes.Black, e.Bounds, sf); 
       } 
      } 
     } 

     public Form1() 
     { 
      InitializeComponent(); 
      LoadData(listView1); 
      LoadData(listView2); 
      LoadData(listView3); 
      LoadData(listView4); 
     } 

     private void LoadData(ListView listView) 
     { 
      listView.Columns.Add("first", 35); 
      listView.Columns.Add("second", 75); 

      for (int i = 0; i < 5; i++) 
      { 
       listView.Items.Add("test"); 
       listView.Items[i].SubItems.Add("test test test test"); 
      } 
     } 

     #region from Form1.Designer 
     /// <summary> 
     /// Required designer variable. 
     /// </summary> 
     private System.ComponentModel.IContainer components = null; 

     /// <summary> 
     /// Clean up any resources being used. 
     /// </summary> 
     /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 
     protected override void Dispose(bool disposing) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 

     #region Windows Form Designer generated code 

     /// <summary> 
     /// Required method for Designer support - do not modify 
     /// the contents of this method with the code editor. 
     /// </summary> 
     private void InitializeComponent() 
     { 
      this.listView1 = new System.Windows.Forms.ListView(); 
      this.listView2 = new System.Windows.Forms.ListView(); 
      this.listView3 = new System.Windows.Forms.ListView(); 
      this.listView4 = new System.Windows.Forms.ListView(); 
      this.SuspendLayout(); 
      // 
      // listView1 
      // 
      this.listView1.Location = new System.Drawing.Point(12, 12); 
      this.listView1.Name = "listView1"; 
      this.listView1.Size = new System.Drawing.Size(121, 116); 
      this.listView1.TabIndex = 0; 
      this.listView1.UseCompatibleStateImageBehavior = false; 
      this.listView1.View = System.Windows.Forms.View.Details; 
      // 
      // listView2 
      // 
      this.listView2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 
      this.listView2.Location = new System.Drawing.Point(151, 12); 
      this.listView2.Name = "listView2"; 
      this.listView2.Size = new System.Drawing.Size(121, 116); 
      this.listView2.TabIndex = 1; 
      this.listView2.UseCompatibleStateImageBehavior = false; 
      this.listView2.View = System.Windows.Forms.View.Details; 
      // 
      // listView3 
      // 
      this.listView3.Location = new System.Drawing.Point(12, 134); 
      this.listView3.Name = "listView3"; 
      this.listView3.OwnerDraw = true; 
      this.listView3.Size = new System.Drawing.Size(121, 116); 
      this.listView3.TabIndex = 2; 
      this.listView3.UseCompatibleStateImageBehavior = false; 
      this.listView3.View = System.Windows.Forms.View.Details; 
      this.listView3.DrawSubItem += new System.Windows.Forms.DrawListViewSubItemEventHandler(this.ListViewDrawSubItem); 
      // 
      // listView4 
      // 
      this.listView4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 
      this.listView4.Location = new System.Drawing.Point(151, 134); 
      this.listView4.Name = "listView4"; 
      this.listView4.OwnerDraw = true; 
      this.listView4.Size = new System.Drawing.Size(121, 116); 
      this.listView4.TabIndex = 3; 
      this.listView4.UseCompatibleStateImageBehavior = false; 
      this.listView4.View = System.Windows.Forms.View.Details; 
      this.listView4.DrawSubItem += new System.Windows.Forms.DrawListViewSubItemEventHandler(this.ListViewDrawSubItem); 
      // 
      // Form1 
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
      this.ClientSize = new System.Drawing.Size(284, 262); 
      this.Controls.Add(this.listView4); 
      this.Controls.Add(this.listView3); 
      this.Controls.Add(this.listView2); 
      this.Controls.Add(this.listView1); 
      this.Name = "Form1"; 
      this.Text = "Form1"; 
      this.ResumeLayout(false); 

     } 

     #endregion 

     private System.Windows.Forms.ListView listView1; 
     private System.Windows.Forms.ListView listView2; 
     private System.Windows.Forms.ListView listView3; 
     private System.Windows.Forms.ListView listView4; 
     #endregion 

     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Run(new Form1()); 
     } 
    } 
} 
+0

您需要对齐列中的值吗?你有没有考虑添加一列? –

+0

@HansPassant我有。我正在显示家庭数据;一排/一家。孩子的数量是任意的;在大多数情况下是低的,但在数据集中有一些有一堆。有一个愿望是避免有大量的列和由此产生的水平滚动条,只有几个百分比的行需要某些东西。由于单元格的默认工具提示要缩小以避免被截断,因此单元格的全文提供了另一种方式来查看所有异常值而不滚动。这在当时似乎是一个合理的妥协。 Kid 1 ... Kid N列是后备选项。 –

回答

6

我发现了绘图子项目方法的或有实现。我的主要注意事项是标签大小是固定的(尽管如果需要更改它,我可以下降到win32)。并且在我的机器上工作时所需的标志组合在MSDN中报告为互不兼容。

private void ListViewDrawSubItem(object sender, DrawListViewSubItemEventArgs e) 
{ 
    //toggle colors if the item is highlighted 
    if (e.Item.Selected && e.Item.ListView.Focused) 
    { 
     e.SubItem.BackColor = SystemColors.Highlight; 
     e.SubItem.ForeColor = e.Item.ListView.BackColor; 
    } 
    else if (e.Item.Selected && !e.Item.ListView.Focused) 
    { 
     e.SubItem.BackColor = SystemColors.Control; 
     e.SubItem.ForeColor = e.Item.ListView.ForeColor; 
    } 
    else 
    { 
     e.SubItem.BackColor = e.Item.ListView.BackColor; 
     e.SubItem.ForeColor = e.Item.ListView.ForeColor; 
    } 

    // Draw the standard header background. 
    e.DrawBackground(); 

    //add a 2 pixel buffer the match default behavior 
    Rectangle rec = new Rectangle(e.Bounds.X + 2, e.Bounds.Y+2, e.Bounds.Width - 4, e.Bounds.Height-4); 

    //TODO Confirm combination of TextFormatFlags.EndEllipsis and TextFormatFlags.ExpandTabs works on all systems. MSDN claims they're exclusive but on Win7-64 they work. 
    TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.EndEllipsis | TextFormatFlags.ExpandTabs | TextFormatFlags.SingleLine; 

    //If a different tabstop than the default is needed, will have to p/invoke DrawTextEx from win32. 
    TextRenderer.DrawText(e.Graphics, e.SubItem.Text, e.Item.ListView.Font, rec, e.SubItem.ForeColor, flags); 
}