Laden...

Listbox selbst gemacht. Mit Bildern und einfach.

Erstellt von Robertico vor 17 Jahren Letzter Beitrag vor 17 Jahren 8.028 Views
R
Robertico Themenstarter:in
344 Beiträge seit 2006
vor 17 Jahren
Listbox selbst gemacht. Mit Bildern und einfach.

Hi Alle.

Habe mir eine Listbox selbst gemacht. Zum ersten mal so etwas.
War erstaunt, wie einfach das geht. Und dieser Artikel hätte mir sehr geholfen. Darum schreibe ich ihn.
Allerdings bitte ich auch die, die Verbesserungen/ Kritik haben, diese zu äußern.

Bin nicht empfindlich.

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Codecompletition  
{
    public struct Items
    {
        public Items(string txt, int imgNummer, Color col)
        {
            text = txt;
            imgNr = imgNummer;
            color = col;
        }
        // hier kann man noch alles mögliche unterbringen
        // BackColor, Font (mit Vorsicht, da feste Größe)
        // muss man dann im Paint umsetzten.
        public string text;
        public int imgNr;
        public Color color;
    }
    public partial class CodeListBox : Form
    {
        Timer sortTimer = new Timer();
        ImageList images = new ImageList();
        List<Items> items = new List<Items>();
        int highLightedItem = -1;
        string selectedItem = "";
        int selectedIndex = -1;
        public CodeListBox()
        {
            InitializeComponent();
            panel1.Paint += new PaintEventHandler(panel1_Paint);
            vScrollBar1.ValueChanged += new EventHandler(vScrollBar1_ValueChanged);
            panel1.MouseDown += new MouseEventHandler(panel1_MouseDown);
            sortTimer.Interval = 10;
            sortTimer.Tick += new EventHandler(sortTimer_Tick);
        }

        void sortTimer_Tick(object sender, EventArgs e)
        {
            // eigendlich ist dieser Timer nur aus einer Art Ratlosigkeit entstanden. 
            // Wenn ich bei jedem AddItem sortiere, so wird das ganze lahm.
            items.Sort( new MyComparer());
            // Neu Zeichnen einläuten. Es hat sich etwas verändert
            panel1.Invalidate();
            sortTimer.Stop();
        }

        void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            // Da mein Fenster eine feste Größe hat, kann ich hier ganz einfach ermitten, auf was der User geklickt hat.
            // sind immer 16 Pixel Abstand.
            highLightedItem = e.Y / 16 + vScrollBar1.Value;
            selectedItem = items[highLightedItem].text;
            selectedIndex = highLightedItem;
            // Neu Zeichnen einläuten. Es hat sich etwas verändert
            panel1.Invalidate();
        }
        public string SelectedItem
        {
            get { return selectedItem; }
            set
            {
                // kommt noch. Damit man den Index selbst setzen kann
            }
        }
        public int SelectedIndex
        {
            get { return selectedIndex; }
            set
            {
                // kommt noch. Damit man den Index selbst setzen kann
            }
        }
        void vScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            // Neu Zeichnen einläuten. Es hat sich etwas verändert
            panel1.Invalidate();
        }

        void panel1_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.Clear(Color.White);
            // float txtHeight = e.Graphics.MeasureString("W", this.Font).Height;
            // habe ich nicht genommen, da ich eine feste Größe habe und die Bilder auch die Größe vorgeben
            for (int i = vScrollBar1.Value; i < Math.Min(vScrollBar1.Value + 10, vScrollBar1.Maximum); i++)
            {
                if (highLightedItem == i)
                {
                    Pen pen = new Pen(Color.CornflowerBlue,16f);
                    // wollte kein Rectangle füllen, daher habe ich einfach die Linie dicker gemacht. Soll Windows sich darum kümmern
                    e.Graphics.DrawLine(pen, new Point(20, (i - vScrollBar1.Value) * 16 + 8), new Point(this.Width, (i - vScrollBar1.Value) * 16 + 8));
                    e.Graphics.DrawString(items[i].text, this.Font, Brushes.White, 20, (i - vScrollBar1.Value) * 16);
                }
                else
                    e.Graphics.DrawString(items[i].text, this.Font, Brushes.Black, 20, (i - vScrollBar1.Value) * 16);
                e.Graphics.DrawImage(images.Images[items[i].imgNr], 2, (i - vScrollBar1.Value) * 16, 12, 12);
            }
        }
        public void AddImage(Image img)
        {
            images.Images.Add(img);
        }
        public void SetImageList(ImageList imgList)
        {
            images = imgList;
        }
        public void AddItem(string text, int imgNr, Color col)
        {
            items.Add(new Items(text, imgNr, col));
            // das Maximum der ScrollBar wird auf die Länge der Liste gesetzt. Einfacher.
            vScrollBar1.Maximum = items.Count - 1;
            if (!sortTimer.Enabled)
                sortTimer.Start();
        }
    }
    public class MyComparer : IComparer<Items>
    {
        public int Compare(Items x, Items y)
        {
            // Da habe ich gesucht um das zu finden ;) F1 hat mir geholfen.
            return ((Items)x).text.CompareTo(((Items)y).text);
        }
    }
}

Ein Wort noch zum Paint:

Da ich ja nur 10 Zeilen sichtbar habe, brauchen ja auch nur diese gezeichnet werden. Man denkt zwar, oben und unten gehts weiter, aber dem ist nicht so.

Gruß Robert

Kompl. Projekt im Anhang

E
26 Beiträge seit 2004
vor 17 Jahren

hallo,

soviel wie ich sehen kann ist diese Listbox konkret in einer Form verankert, also nicht unbedingt wiederverwendbar. Besser wäre daraus ein einzelnes Control zu machen, welches in einer Form eingebunden werden kann.

        // Da mein Fenster eine feste Größe hat, kann ich hier ganz einfach ermitten, auf was der User geklickt hat.  
        // sind immer 16 Pixel Abstand

diese Annahme hat auch nicht unbedingt allgemeingültigen Character.

elli

R
Robertico Themenstarter:in
344 Beiträge seit 2006
vor 17 Jahren

Hallo elli,

danke für die Antwort.

Sicher gibt es Verbesserungen, da bin ich mir bewusst. Ich lerne ja noch.

Das Script habe ich aber einfach so mit ein paar Änderungen in ein bestehendes Projekt eingebunden und damit das Completition-Teil von CSharpDevelop ersetzt.

Wesendlich handlicher (Da ich weis was abläuft) und schneller.

Die Idee von Dir, daraus ein Control zu machen, werde ich auf jeden Fall aufgreifen.

Muss ich halt noch etwas lernen.

Aber genau feststellen, wo ich bin, kann ich. Jede Zeile ist 16 Pixel groß. Dadurch weis ich genau, in welcher der angezeigten Zeile geclickt wurde.

Wollte eigendlich nur zeigen, wie einfach das sein kann.

Gruß Robert

PS: Wenn mir jemand sagen kann, wie ich diesen Timer ersetzten könnte, wäre das nicht schlecht.

4.221 Beiträge seit 2005
vor 17 Jahren

So geht es noch einfacher.

ImageListBox

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

R
Robertico Themenstarter:in
344 Beiträge seit 2006
vor 17 Jahren

Wollte das nicht von Listbox ableiten, da durch das drum herum diese bei vielen Einträgen langsamer ist.

Brauche ja nur Bild und Text. 🙂

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Robertico,

naja, ein Control sollte nun mal eigenständig sein und auch von Control oder einer Unterklasse von Control erben. Dabei bietet sich die Unterklasse an, die schon "am nächsten dran" ist, an dem was man will. Vielleicht wäre da ListView geeignet, denn das hat schon einen VirtualMode, den man benutzen kann, um Probleme mit vielen Einträgen zu vermeiden.

herbivore

R
Robertico Themenstarter:in
344 Beiträge seit 2006
vor 17 Jahren

Hallo herbivore,

Ein wenig mache ich das ja um zu lernen. Daher möchte ich auch alles selbst machen (was geht).
Habe jetzt Panel gewählt. Ist das OK?

Gruß Robert

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Robertico,

tja, was heißt schon ok. Sicher kann man ein Panel als Basis nehmen. Allerdings ist dann m.E. sehr viel mehr zu programmieren, als wenn man eine ListBox oder ein ListView als Basis nimmt.

herbivore

R
Robertico Themenstarter:in
344 Beiträge seit 2006
vor 17 Jahren

Original von herbivore
Allerdings ist dann m.E. sehr viel mehr zu programmieren, als wenn man eine ListBox oder ein ListView als Basis nimmt.

Genau das will ich ja.

Wenn ich es kann, kann ich ja den leichteren Weg nehmen. 😉

Gruß Robert