Установка цвета фона в поле заполнения заголовка ListView [дубликат]

Простой код tkinter для Python 3 для установки фонового изображения.

from tkinter import *
from tkinter import messagebox
top = Tk()

C = Canvas(top, bg="blue", height=250, width=300)
filename = PhotoImage(file = "C:\\Users\\location\\imageName.png")
background_label = Label(top, image=filename)
background_label.place(x=0, y=0, relwidth=1, relheight=1)

C.pack()
top.mainloop
3
задан Marek 16 September 2009 в 15:22
поделиться

1 ответ

Я удивлен ответом Джеффри Тан на этот пост. Его решение не может работать, так как код пытается выйти за пределы области клиентского контроля заголовка. hDC, используемый в пользовательском чертеже (и, следовательно, чертеж владельца), предназначен для клиентской области элемента управления и поэтому не может использоваться для рисования в неклиентской области. Область справа справа от самой колонки в элементе управления заголовком находится в неклиентской области. Итак, вам нужно другое решение.

Возможные решения

  1. Привет, технический и частично эффективный

Вы может разрешить рисование за пределами клиентской области с помощью вызова GetDC() WinAPI:

[System.Runtime.InteropServices.DllImport("user32")]
private static extern IntPtr GetDC(IntPtr hwnd);
[System.Runtime.InteropServices.DllImport("user32")]
private static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc);

public static IntPtr GetHeaderControl(ListView list) {
    const int LVM_GETHEADER = 0x1000 + 31;
    return SendMessage(list.Handle, LVM_GETHEADER, 0, 0);
}

В обработчике события рисования столбца вам понадобится что-то вроде этого:

if (e.ColumnIndex == 3) //last column index
{
  ListView lv = e.Header.ListView;
  IntPtr headerControl = NativeMethods.GetHeaderControl(lv);
  IntPtr hdc = GetDC(headerControl);
  Graphics g = Graphics.FromHdc(hdc);

  // Do your extra drawing here
  Rectangle rc = new Rectangle(e.Bounds.Right, //Right instead of Left - offsets the rectangle
            e.Bounds.Top, 
            e.Bounds.Width, 
            e.Bounds.Height);

    e.Graphics.FillRectangle(Brushes.Red, rc);

  g.Dispose();
  ReleaseDC(headerControl, hdc);
}

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

  1. Низкотехнологичный, но уродливый

Добавьте дополнительный пустой столбец к вашему контроль, владелец рисует его, смотря, как вы хотите, сделайте его очень широким и отключите горизонтальную прокрутку (необязательно).

Я знаю, что это ужасно, но вы ищете предложения:)

  1. Наиболее эффективны, но все же не идеальны

Используйте ObjectListView . Эта оболочка вокруг .NET ListView позволяет добавлять наложения в ваш список - оверлей можно рисовать в любом месте ListView, включая заголовок. [Объявление: Я автор ObjectListView, но я все еще думаю, что это лучшее решение]

public class HeaderOverlay : AbstractOverlay
{
    public override void Draw(ObjectListView olv, Graphics g, Rectangle r) {
        if (olv.View != System.Windows.Forms.View.Details)
            return;

        Point sides = NativeMethods.GetColumnSides(olv, olv.Columns.Count-1);
        if (sides.X == -1)
            return;

        RectangleF headerBounds = new RectangleF(sides.Y, 0, r.Right - sides.Y, 20);
        g.FillRectangle(Brushes.Red, headerBounds);
        StringFormat sf = new StringFormat();
        sf.Alignment = StringAlignment.Center;
        sf.LineAlignment = StringAlignment.Center;
        g.DrawString("In non-client area!", new Font("Tahoma", 9), Brushes.Black, headerBounds, sf);
    }
}

Это дает следующее: alt text http://i26.tinypic.com/2m7ex .jpg

[Читая этот ответ, я думаю, что это пример слишком тяжелой попытки :) Надеюсь, вы найдете здесь что-то полезное.]

5
ответ дан Grammarian 28 August 2018 в 06:40
поделиться
  • 1
    Спасибо за отличный ответ. В нашем случае ObjectListView будет излишним. Ваше первое решение достаточно и работает достаточно хорошо в нашем сценарии. У вас небольшая ошибка в коде - естественно следует нарисовать экземпляр g, а не на оригинальную e.Graphics: e.Graphics.FillRectangle (Brushes.Red, rc); // должен быть g.FillRectangle Импортирован метод SendMessage: [DllImport («user32.dll», CharSet = CharSet.Auto)] public static extern IntPtr SendMessage (дескриптор IntPtr, int messg, int wparam, int lparam) ; – Marek 17 September 2009 в 09:28
  • 2
    Да, ты совершенно прав – Grammarian 17 September 2009 в 20:37
  • 3
    OLV отлично, но я считаю, что вам нужно обрабатывать WM_PAINT и WM_ERASEBKGND в HeaderControl, чтобы иметь возможность полностью настраивать заголовок. Что-то вроде этого: codeproject.com/Articles/4243/… – thims 8 November 2012 в 16:57
Другие вопросы по тегам:

Похожие вопросы: