Проблемы со списком при визуализации текста в режиме рисования владельцем

Я пытаюсь реализовать нарисованного владельца ListView, потому что базовый элемент управления съедает символ табуляции, который мне нужен для выравнивания значений в столбце.

Используя пример из MSDN в качестве базы мне удалось приблизиться. Единственная проблема, с которой я все еще сталкиваюсь, заключается в том, что точки многоточия, используемые, когда текст не помещается в столбце, расположены гораздо ближе друг к другу, чем при визуализации текста по умолчанию; Дело в том, что если шрифт полужирный, точки переходят вместе в подчеркивание.

Программа ниже демонстрирует проблему. Он имеет 4 ListViews: два сверху нарисованы с использованием рендеринга по умолчанию. Два внизу изображены владельцем, а пара в правой части выделена жирным шрифтом. Из соображений длины я удалил все, что мне не нужно, чтобы продемонстрировать проблему, поэтому в ownerdawn ListViews нет заголовков столбцов.

Глядя на увеличенный снимок экрана, периоды многоточия в изображении владельца ListView расположены на расстоянии одного пикселя друг от друга; те, что на чертеже по умолчанию, имеют интервал в два пикселя. Когда полужирный шрифт расширяет точки до двух пикселей, нарисованные владельцем сливаются в сплошную массу, которая выглядит как подчеркивание.

Есть и другие незначительные отличия в визуализации текста; но многоточие - единственное, что легко увидеть без увеличения. Однако эти различия заставляют меня подозревать, что проблема носит более общий характер. Возможно, GDI или 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());
        }
    }
}

person Dan Is Fiddling By Firelight    schedule 02.12.2011    source источник
comment
Вам нужно выровнять значения в столбце? Думали ли вы о добавлении столбца?   -  person Hans Passant    schedule 02.12.2011
comment
@HansPassant У меня есть. Я показываю семейные данные; один ряд / семья. Количество малышей произвольное; в большинстве случаев низкий, но есть несколько, у которых в наборе данных много. Есть желание избежать большого количества столбцов и результирующей горизонтальной полосы прокрутки для чего-то, что требуется только для нескольких процентов строк. Поскольку всплывающая подсказка по умолчанию для ячейки, которая должна сужаться, чтобы избежать усечения, представляет собой полный текст ячейки, она дает альтернативный способ увидеть все выбросы без прокрутки. В то время это казалось разумным компромиссом. Малыш 1 ... Столбцы Малыша N - это запасной вариант.   -  person Dan Is Fiddling By Firelight    schedule 02.12.2011


Ответы (1)


Я нашел условную реализацию для метода подпункта рисования. Основные предостережения, которые у меня есть, заключаются в том, что размер вкладки фиксирован (хотя я мог бы перейти на 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 tab stop 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);
}
person Dan Is Fiddling By Firelight    schedule 06.12.2011