Отображение пиктограмм размером 128x128 пикселей или больше в сетке в ListView - PullRequest
44 голосов
/ 09 июля 2009

Оригинальный вопрос (см. Обновление ниже)

У меня есть программа WinForms, которая нуждается в приличном прокручиваемом элементе управления значками с большими значками (на самом деле размером 128x128 или больше), которые можно щелкнуть до полусвета или дважды щелкнуть, чтобы выполнить какое-либо действие. Предпочтительно, чтобы было минимальное потраченное впустую пространство (под каждым значком могут понадобиться короткие заголовки имен файлов; если имя файла слишком длинное, я могу добавить многоточие).

finished version of listview with proper colors, spacing, etc.
(источник: updike.org )

Я попытался использовать ListView с LargeIcon (по умолчанию .View), и результаты разочаровывают:

screenshot showing tiny icons in LargeIcon view
(источник: updike.org )

Возможно, я неправильно заполняю элемент управления? Код:

        ImageList ilist = new ImageList();
        this.listView.LargeImageList = ilist;
        int i = 0;
        foreach (GradorCacheFile gcf in gc.files)
        {
            Bitmap b = gcf.image128;
            ilist.Images.Add(b);
            ListViewItem lvi = new ListViewItem("text");
            lvi.ImageIndex = i;
            this.listView.Items.Add(lvi);
            i++;
        }

Мне нужны большие значки с небольшим пустым пространством, а не большое пустое пространство с смущающе маленькими значками.

  1. Есть ли элемент управления .NET, который делает то, что мне нужно?
    • Есть ли любимый сторонний элемент управления, который делает это?
    • Если нет, какой элемент управления лучше всего унаследовать и настроить для его работы?
    • Должен ли я сломаться и создать собственный элемент управления (с которым у меня большой опыт ... просто не хочу переходить к этому крайнему виду, так как это несколько связано).

Я нашел этот урок о OwnerDraw , но работа с ним в основном составляет 3 или 4 выше, поскольку эта демонстрация просто показывает, как оживить строки в подробном представлении.

Обновление

Добавление строки

ilist.ImageSize = new Size(128, 128);

до того, как цикл for устранил проблему размера, но теперь изображения палитрированы до 8-битных (выглядит как системные цвета?), Хотя отладчик показывает, что изображения вставляются в ImageList как 24bpp System.Drawing.Bitmap's :

large icons, finally
(источник: updike.org )

  1. Как я могу (могу ли я?) Заставить изображения отображаться в полном 24-битном цвете?
    • Расстояние между значками все еще довольно расточительно ... как это исправить? Можно я?

Обновление 2

Наряду с добавлением строки

ilist.ColorDepth = ColorDepth.Depth24Bit;

следующий после установки ilist.ImageSize, я последовал совету арбитра и изменил интервал:

[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

public int MakeLong(short lowPart, short highPart)
{
    return (int)(((ushort)lowPart) | (uint)(highPart << 16));
}

public void ListView_SetSpacing(ListView listview, short cx, short cy)
{
    const int LVM_FIRST = 0x1000;
    const int LVM_SETICONSPACING = LVM_FIRST + 53;
    // http://msdn.microsoft.com/en-us/library/bb761176(VS.85).aspx
    // minimum spacing = 4
    SendMessage(listview.Handle, LVM_SETICONSPACING,
    IntPtr.Zero, (IntPtr)MakeLong(cx, cy));

    // http://msdn.microsoft.com/en-us/library/bb775085(VS.85).aspx
    // DOESN'T WORK!
    // can't find ListView_SetIconSpacing in dll comctl32.dll
    //ListView_SetIconSpacing(listView.Handle, 5, 5);
}

///////////////////////////////////////////////////////////

ListView_SetSpacing(this.listView, 128 + 12, 128 + 4 + 20);

Элемент управления ListView может быть не идеальным или иметь значения по умолчанию (например, свойство Spacing), но я рад, что мог бы приручить его, в конце концов:

alt text
(источник: updike.org )

Между прочим, чтобы поддерживать правильное соотношение сторон для миниатюр, мне пришлось создавать собственные битовые карты 128x128, очищать фон, чтобы соответствовать элементу управления, и центрировать эти изображения:

public void CenterDrawImage(Bitmap target, Color background, Bitmap centerme)
{
    Graphics g = Graphics.FromImage(target);
    g.Clear(background);
    int x = (target.Width - centerme.Width) / 2;
    int y = (target.Height - centerme.Height) / 2;
    g.DrawImage(centerme, x, y);
    g.Dispose();
}

Ответы [ 5 ]

13 голосов
/ 09 июля 2009

Для обновления:

  1. Установка глубины цвета списка изображений в дополнение к размеру изображения (ilist.ColorDepth = ColorDepth.Depth24Bit)
  2. WinForms ListView не имеет возможности изменять интервал значков, однако это легко сделать с помощью Win32. Вам необходимо отправить LVM_SETICONSPACING в свой ListView (есть много руководств по использованию функции win32 SendMessage в .net, поэтому я думаю, что этого направления должно быть достаточно для вас).
5 голосов
/ 13 июля 2009

ObjectListView (обертка с открытым исходным кодом вокруг .NET ListView) позволяет легко рисовать представление Tile. Посмотрите на сложное представление на демо, переключитесь на представление Tile, когда пользовательское рисование включено: owner drawn tile view
(источник: sourceforge.net )

Если вам нужно только изображение размером 128x128 плюс некоторые детали текста, вам даже не нужно будет рисовать его владельцем. Вы можете предоставить ему большой список изображений, а затем отметить, какие биты текстовой информации вы хотите показать на плитке, используя IsTileViewColumn.

5 голосов
/ 09 июля 2009

Вы можете использовать FlowLayoutPanel и удалить в нем графические окна. Установите для Picturebox размер 128x128, а для параметра sizemode - «zoom» (Это позволяет изменить размер изображения без потери соотношения сторон). Вы даже можете программно добавлять графические окна.

PictureBox pb = New Picturebox;
 pb.image = gcf.image128;
 FlowLayoutPanel1.Controls.Add(pb)

Поскольку у вас должна быть метка под картинкой, вы можете создать пользовательский контроль, как сказал Пастор, и все, что у него есть, - это коробочка с картинками и метка под ней. Тогда это будет контрольный экземпляр, который вы добавите в свою панель Flowlayout.

2 голосов
/ 09 июля 2009

Отказ от ответственности: я работаю на Atalasoft

В нашем .NET Imaging SDK есть элемент управления миниатюрами изображений, DotImage

1 голос
/ 09 июля 2009

Создание пользовательского элемента управления не будет слишком плохим. Я бы унаследовал от Panel или Usercontrol, поскольку я считаю, что оба автоматически добавляют полосы прокрутки для содержимого.

Динамическое добавление контейнеров (например, PictureBoxes) и подписей для каждого изображения, обработка события mousedown или mouseclick для контейнера и, возможно, рисование красного квадрата вокруг него, чтобы показать, что он выбран. «Самая трудная» часть - это повторная дискретизация изображения до 128x128, если они уже не такого размера, и даже это легко сделать с помощью GDI +.

...