Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von progger
Thema: Systemmonitor
Am im Forum: Projekte

Hallo zusammen,

Zitat
Original von VuuRWerK
Ich glaub es gibt eine Möglichkeit einen Wert .NET zubekommen welcher die Höhe x Breite angibt wo schon Taskbar etc abgezogen sind.
Ganz genau! Und zwar gibt es dafür die Eigenschaft WorkingArea der Screen-Klasse.

Gruß,
Thomas

Thema: Was sind hier für euch die Softwareperlen?
Am im Forum: Smalltalk

Hallo,

Mir sind jetzt spontan folgende Perlen eingefallen:

Dateiassoziation
[Tutorial] Zeichnen in Windows-Programmen (Paint/OnPaint, PictureBox)
[Tutorial] Alles über Dateien 2.0

Wenn ich noch welche finde, lasse ich sie euch natürlich wissen.

Gruß,
Thomas

Thema: Linie im Form zeichnen und verschieben
Am im Forum: Grafik und Sound

Hallo dr4g0n76,

Du sollst doch nicht einfach zusammenfassen, was in meinem (und in herbivore's) Artikel steht. Dann bekomm ich doch keine Hits mehr

Gruß,
Thomas

Thema: Linie im Form zeichnen und verschieben
Am im Forum: Grafik und Sound

Hallo BoKat,

Eigentlich kannst du die Neuerungen von .NET 3.0 überhaupt nicht mit Visual Studio 2005 nutzen. Es gibt aber Erweiterungen, mit denen du die neuen Features trotzdem teilweise hernehmen kannst (siehe Microsoft veröffentlicht .NET Framework 3.0 Final), funktioniert aber NICHT für die Express Editionen und du hast da keinen Designer für WPF oder ähnliches. Dafür musst du auf das nächste Visual Studio, Codename "Orcas", warten.

Gruß,
Thomas

Thema: Generische Vektorklasse und operator+
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo Therion,

Schau dir mal Operator Overloading with Generics und
Using generics for calculations bei Codeproject an.

Gruß,
Thomas

Thema: csc.exe mitliefern?
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Hallo Quick,

Die csc.exe sowie die benötigten Assemblies sind alle bereits im Framework erhalten und werden bei dessen Installation in den Ordner "\Windows\Microsoft.NET\Framework\v<fw-version>\" kopiert.

Gruß,
Thomas

Thema: .Net um Scriptsprache erweitern
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo C#Test,

Ja, ich kann dir einen Hinweis geben: Benutze die Suche bevor du eine Frage stellst . Dann hättest du u.a. Scriptsprache und Mini-Skriptsprache entwickeln gefunden.

Gruß,
Thomas

Thema: SharpZipLib - und komplette Verzeichnisstruktur zippen
Am im Forum: Rund um die Programmierung

Hallo Vergaserbirndl,

Das Projekte-Forum ist zum Vorstellen eigener Projekte da.
==> Verschoben nach "Rund um die Programmierung"

Gruß,
Thomas

Thema: Skalierbare "Bars" in SVG...wie zu realisieren?
Am im Forum: Grafik und Sound

Hallo BenFire,

Wenn du es wirklich so machen willst: Am besten du fügst den SVG-Code einfach in deinem Programm zusammen. Das kannst du entweder mit einer Klasse machen, der du alle nötigen Informationen gibt und dir dann dein Diagramm bastelt (die geschicktere Variante) oder mit einer einfachen Methode. Die x-Koordinaten würde ich an deiner Stelle in einer Variable speichern und dann immer erhöhen wenn du zum nächsten Balken gehst. Den Rest müsstest du eigentlich selbst zusammenbringen.

Gruß,
Thomas

Thema: Skalierbare "Bars" in SVG...wie zu realisieren?
Am im Forum: Grafik und Sound

Hallo BenFire,

Wenn du sowieso eine C#-Anwendung hast, würde ich an deiner Stelle das visualisieren der Daten selbst mit GDI+ übernehmen. Das ist nicht recht viel komplizierter und du sparst dir damit einige Inkompatibilitäten bei der Darstellung von SVG (was zum Beispiel wenn beim Nutzer keine Anwendung zum Betrachten von SVG-Grafiken vorhanden ist? Mitliefern?). Schau dir vielleicht mal [Tutorial] Zeichnen in Windows-Programmen (Paint/OnPaint, PictureBox) an. Das könnte dir helfen.

Gruß,
Thomas

Thema: Skalierbare "Bars" in SVG...wie zu realisieren?
Am im Forum: Grafik und Sound

Zitat
Original von Borg
Soweit ich weiß, kann nur der IE6 kein SVG. Wie es mit dem 7er aussieht, kann ich nicht sagen.
Ich bin mir ziemlich sicher, dass auch in der 7er Version des Internet Explorers keine Unterstützung für SVG ist. Wenn überhaupt kommt dies erst in einer späteren Version. So viel ich weiß ist etwas für IE7.2 geplant. Ich muss dazu aber sagen, dass es auch schon für IE7 geplant war.

Thema: Skalierbare "Bars" in SVG...wie zu realisieren?
Am im Forum: Grafik und Sound

Hallo BenFire,

Du musst uns mehr Infos geben: Mit was arbeitest du (außer SVG)? ASP.NET, PHP, JSP, ...? Also ich geh davon aus, dass es um eine Webanwendung geht. Oder lieg ich da falsch?
Ansonsten muss ich dir sagen, dass SVG eigentlich nicht allzu gut geeignet ist: Es gibt noch kaum wirklich gute Umsetzungen, vor allem bei den Browsern. Vielleicht solltest du nochmal überdenken, ob du das nicht anders angehst.

Ich hoffe, ich konnte dir helfen!

Gruß,
Thomas

Thema: gutes openbook
Am im Forum: Buchempfehlungen

Hallo ApfeL,

Hast du schon das Das .NET BlogBook ausprobiert?

Gruß,
Thomas

Thema: Index von Listview abfragen
Am im Forum: GUI: Windows-Forms

Hallo webstarg,

Dein Code-Beispiel ist für mich verwirrend. Warum versuchst du das Element an der -1. Stelle (die es ja gar nicht gibt) abzufragen?

Und was genau einst du mit "abfragen, ob etwas ausgewählt is oder nicht"?
a) ob überhaupt ein Element ausgewählt wurde: ListView.SelectedIndices/Items.Count != 0
b) ob ein bestimmtes Element ausgewöhlt wurde: ListView.SelectedIndices.Contains(index) oder ListView.SelectedItems.Contains(item)

Ich hoffe ich konnte dir helfen!

Gruß,
Thomas

Thema: Automatische Prüfung auf eine neue Version
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Hallo outi,

Das von dir geschilderte Verfahren nennt sich ClickOnce. Danach kannst du hier im Forum suchen (wurde schon sehr offt behandelt, auch alle möglichen Fehlrverhalten).
Ansonsten gibt es noch diverse Update-Manager und -Bibliotheken. Kannst auch mal im Forum hier suchen (wenn ich mich recht erinner, gibt es sogar einen im Projekte-Forum).

Gruß,
Thomas

Thema: Dateiassoziation: Neue Dateinamen an die laufende Anwendung übergeben
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo xxxprod,

Das ist grundsätzlich so und hat nichts mit dem Beispiel hier zu tun. Höchstwahrscheinlich hast du einen Fehler in deinem eigenen Code gemacht. Schau dir am besten mal den FAQ-Beitrag [FAQ] Controls von Thread aktualisieren lassen (Invoke-/TreeView-Beispiel) an.

Gruß,
Thomas

Thema: Microsoft Server Down
Am im Forum: Smalltalk

Alles normal.

EDIT: Oh, ich hab deine Antwort übersehen, LastGentleman. Sorry!

Thema: ESD-Schutz
Am im Forum: Smalltalk

Hallo zusammen,

Ich habe mich (bis jetzt) auch noch nie mehr davor geschützt, als Heizung-Anfassen oder ähnliches.
Aber vielen Dank, ich finde diesen Thread und die Beiträge in Was meint Ihr zu dieser PC - Zusammenstellung? sehr hilfreich und werde mir auch eine ESD-Ausrüstung anschaffen. Das kommt bei mir auch gerade richtig, weil ich mir in den nächsten Monaten einen neuen PC anschaffen und diesen auch selbst zusammenbauen will.

Gruß,
Thomas

Thema: Screenshot von Video
Am im Forum: Grafik und Sound

Hallo Nogger,

Das, was du machen willst, klingt wie eine Art "Ambilight". Lieg ich richtig?

Mir fällt keine Möglichkeit ein, das zu machen. Weil man eben ja immer nur ein schwarzes Bild bekommt. Das liegt an der Overlay-Technik (oder wie hieß das gleich nochmal?), eben wie Videos angezeigt werden: Die Grafikkarte fügt erst anschließend das Bild ein, direkt bei der Ausgabe.

Ich drück dir die Daumen, dass du noch eine Lösung findest. Wennich noch was rausfinden sollte, lasse ich es dich natürlich wissen.

In diesem Sinne: Frohes neues Jahr und viele Grüße,
Thomas

Thema: Frohes neues Jahr
Am im Forum: Smalltalk

Hallo zusammen,

Ich kann mich nur anschließen und wünsche euch allen ein FROHES NEUES JAHR 2007!!!!!!!!!!!!

VIele Grüße,
Thomas

Thema: Welche AddOns für Visual Studio 2005 setzt ihr ein?
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Hallo Atze,

Dazu gibt es schon einen thread, siehe Visual Studio Erweiterungen.
Dort kannst du auch lesen, welche Erweiterungen ich einsetze .

Gruß,
Thomas

Thema: Gibt es sowas wie AutoRedraw?
Am im Forum: Grafik und Sound

Hallo areopag,

Schau dir dazu mal folgendes Tutorial von herbivore an: [Tutorial] Zeichnen in Windows-Programmen (Paint/OnPaint, PictureBox)

Gruß,
Thomas

Thema: Der Weihnachtsthread
Am im Forum: Ankündigungen

Zitat
Original von Fabian
allerdings könnte es kompliziert werden, 6950 Geschenke zu besorgen :(.
Oh ja!! Ich hab ja bei 10 Geschenken schon Probleme .

Thema: Der Weihnachtsthread
Am im Forum: Ankündigungen

Ich wünsch euch auch allen von Herzen ein frohes Weihnachtsfest!! Und schöne Geschenke .
Schade, dass wir Weihanchten nicht in unsere ganzen "Familie" feiern können . Und jeder schenkt jedem was :D.

Viele weihnachtliche Grüße,
Thomas

Thema: Microsoft® Visual Studio® 2005 Service Pack 1
Am im Forum: Szenenews

Oh, Mann!! Ich könnt mich echt ohrfeigen: Jetzt habe ich ausversehen die deutsche Version des SP geladen, obwohl ich das englische VS drauf hab!! X(
Jetzt darf ich nochmal alles saugen und das bei einem Volumentarif ...

Thema: .gif als .gif speicher - ist nichtmehr animiert
Am im Forum: Grafik und Sound

Hallo basi,

Das Trennen und Zusammenfügen der einzelnen Frames musst du wahrscheinlich selbst erledigen. Schau dir dazu am besten mal NGif an.

Gruß,
Thomas

Thema: [Tutorial] Gezeichnete Objekte mit der Maus verschieben
Am im Forum: Artikel

Beispielanwendung

Im Grunde ist mein Beispiel herbivore's sehr ähnlich. Ich hab aber zu dem Rechteck auch noch Kreis und Linie als graphische Objekte hinzugefügt.
In dem Fenster sind drei Buttons, mit denen man zufällig erstellte Objekte hinzufügen kann. Darunter befindet sich eine TextBox und noch ein Button, mit deren Hilfe man Texte hinzufügenkann.
Das Verschieben geht ganz einfach mit der Maus.

Bitte beachtet auch die Kommentare im Code!

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

public abstract class MyGraphicObject {
    /// <summary>
    /// Dieses Pen-Objekt wird verwendet um zu überprüfen, ob ein
    /// Punkt über der Linie des Objekts liegt. Die Farbe ist
    /// hierfür irrelevant. Als Breite hat sich 4 als sinnvoll erwiesen.
    /// </summary>
    static Pen HitTestPen = new Pen(Brushes.Black, 4);
    Pen _pen;
    bool _bVisible = true;
    GraphicsPath _path = new GraphicsPath();

    public MyGraphicObject(Pen pen) {
        _pen = pen;
    }

    protected GraphicsPath Path {
        get { return _path; }
    }

    public Pen Pen {
        get { return _pen; }
    }

    public bool Visible {
        get { return _bVisible; }
        set { _bVisible = value; }
    }

    /// <summary>
    /// Befindet sich der angegebene Punkt über der Linie des Objekts?
    /// </summary>
    public virtual bool Hit(Point pt) {
        return _path.IsOutlineVisible(pt, HitTestPen);
    }

    /// <summary>
    /// Befindet sich der angegebene Punkt innerhalb des Objekts?
    /// </summary>
    public virtual bool Contains(Point pt) {
        return _path.IsVisible(pt);
    }

    public virtual void Draw(Graphics g) {
        g.DrawPath(_pen, _path);
    }

    /// <summary>
    /// Bewegt das Objekt um deltaX in x-Richtung und deltaY in y-Richtung.
    /// </summary>
    public virtual void Move(int deltaX, int deltaY) {
        Matrix mat = new Matrix();
        mat.Translate(deltaX, deltaY);
        _path.Transform(mat);
    }
}

public class MyRectangle : MyGraphicObject {
    public MyRectangle(Pen pen, Rectangle rect)
        : base(pen) {
        Path.AddRectangle(rect);
    }
}

public class MyCircle : MyGraphicObject {
    public MyCircle(Pen pen, Point center, int radius)
        : base(pen) {
        Path.AddEllipse(center.X - radius, center.Y - radius, 2 * radius, 2 * radius);
    }
}

public class MyLine : MyGraphicObject {
    public MyLine(Pen pen, Point start, Point end)
        : base(pen) {
        Path.AddLine(start, end);
    }
}

public class MyText : MyGraphicObject {
    public MyText(Pen pen, string text, FontFamily family, FontStyle style, float emSize, Point origin)
        : base(pen) {
        Path.AddString(text, family, (int)style, emSize, origin, null);
    }

    public override void Draw(Graphics g) {
        g.FillPath(Pen.Brush, Path);
    }

    public override bool Hit(Point pt) {
        return Contains(pt) || base.Hit(pt);
    }
}

public class MainForm : Form {
    Button _btnAddRectangle;
    Button _btnAddCircle;
    Button _btnAddLine;
    Button _btnAddText;
    TextBox _txtText;
    Label _lblMouseLocation;
    List<MyGraphicObject> _graphicObjects = new List<MyGraphicObject>();
    Rectangle _canvas;
    Random _random = new Random();

    public MainForm() {
        InitializeComponent();
    }

    private void InitializeComponent() {
        _lblMouseLocation = new Label();
        _btnAddCircle = new Button();
        _btnAddLine = new Button();
        _btnAddRectangle = new Button();
        _btnAddText = new Button();
        _txtText = new TextBox();

        // Label, das die Maus-Position anzeigt
        _lblMouseLocation.AutoSize = true;
        _lblMouseLocation.Location = new Point(10, 195);
        _lblMouseLocation.Anchor = AnchorStyles.Left | AnchorStyles.Bottom;

        // Button um einen zufälligen Kreis hinzuzufügen
        _btnAddCircle.Text = "Add Circle";
        _btnAddCircle.Width = 100;
        _btnAddCircle.Location = new Point(10, 210);
        _btnAddCircle.Anchor = AnchorStyles.Left | AnchorStyles.Bottom;
        _btnAddCircle.Click += new EventHandler(AddCircle);

        // Button um eine zufällige Linie hinzuzufügen
        _btnAddLine.Text = "Add Line";
        _btnAddLine.Width = 100;
        _btnAddLine.Location = new Point(120, 210);
        _btnAddLine.Anchor = AnchorStyles.Left | AnchorStyles.Bottom;
        _btnAddLine.Click += new EventHandler(AddLine);

        // Button um ein zufälliges Rechteck hinzuzufügen
        _btnAddRectangle.Text = "Add Rectangle";
        _btnAddRectangle.Width = 100;
        _btnAddRectangle.Location = new Point(230, 210);
        _btnAddRectangle.Anchor = AnchorStyles.Left | AnchorStyles.Bottom;
        _btnAddRectangle.Click += new EventHandler(AddRectangle);

        // Button um Text an einer zufälligen Position hinzuzufügen
        _btnAddText.Text = "Add Text";
        _btnAddText.Width = 100;
        _btnAddText.Location = new Point(120, 235);
        _btnAddText.Anchor = AnchorStyles.Left | AnchorStyles.Bottom;
        _btnAddText.Click += new EventHandler(AddText);

        // TextBox, in die man den text eingeben kann der durch _btnAddText hinzugefügt wird
        _txtText.Text = "Text";
        _txtText.Width = 100;
        _txtText.Location = new Point(10, 237);
        _txtText.Anchor = AnchorStyles.Left | AnchorStyles.Bottom;

        this.Controls.Add(_lblMouseLocation);
        this.Controls.Add(_btnAddCircle);
        this.Controls.Add(_btnAddLine);
        this.Controls.Add(_btnAddRectangle);
        this.Controls.Add(_btnAddText);
        this.Controls.Add(_txtText);
        this.Size = new Size(400, 320);
        // Damit geht das Neuzeichnen viel flüssiger
        this.DoubleBuffered = true;
    }

    protected override void OnPaint(PaintEventArgs e) {
        base.OnPaint(e);
        e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
        // Der Bereich, der neugezeichnet werden soll, wird auf die Zeichenfläche
        // beschränkt, damit Objekte, die darüber hinausschauen abgeschnitten werden.
        Region clip = new Region(_canvas);
        clip.Intersect(e.Graphics.Clip);
        e.Graphics.Clip = clip;
        e.Graphics.Clear(Color.White);
        foreach (MyGraphicObject go in _graphicObjects) {
            go.Draw(e.Graphics);
        }
    }

    Point _lastMouseLocation;
    MyGraphicObject _movingGraphicObject;

    protected override void OnMouseDown(MouseEventArgs e) {
        base.OnMouseDown(e);
        // Wenn die Maus außerhalb der Zeichenfläche gedrückt wurde, wird abgebrochen.
        if (!_canvas.Contains(e.Location)) return;
        // Anderenfalls wird die Liste mit den gezeichneten Objekten von hinten (damit
        // das oberste Objekte gefunden wird) durchgegangen und geprüft, über welchem
        // Objekt die Maus sich befindet. 
        for (int i = _graphicObjects.Count - 1; i ≥ 0; i--) {
            MyGraphicObject go = _graphicObjects[i];
            if (go.Hit(e.Location)) {
                _movingGraphicObject = go;
                break;
            }
        }
        _lastMouseLocation = e.Location;
    }

    protected override void OnMouseMove(MouseEventArgs e) {
        base.OnMouseMove(e);
        if (_movingGraphicObject != null) {
            // Wenn gerade ein Objekt verschoben werden soll, wird die Differenz zur letzten
            // Mausposition ausgerechnet und das Objekt um diese verschoben.
            _movingGraphicObject.Move(e.X - _lastMouseLocation.X, e.Y - _lastMouseLocation.Y);
            _lastMouseLocation = e.Location;
            // Hier könnte man noch optimieren, indem man immer nur den Bereich
            // neuzeichnet, in dem das Objekt bewegt wurde.
            this.Invalidate();
        }
        if (_canvas.Contains(e.Location)) {
            _lblMouseLocation.Text = string.Format("x = {0}; y= {1}", e.X, e.Y);
        }
    }

    protected override void OnMouseUp(MouseEventArgs e) {
        base.OnMouseUp(e);
        _movingGraphicObject = null;
    }

    protected override void OnSizeChanged(EventArgs e) {
        base.OnSizeChanged(e);
        // Wenn sich die Größe des Fensters ändert, wird die Größe der Zeichenfläche angepasst.
        _canvas = new Rectangle(new Point(0, 0),
            new Size(this.ClientSize.Width, this.ClientSize.Height - 70));
        this.Invalidate();
    }

    void AddCircle(object sender, EventArgs e) {
        // Erstellt einen Kreis mit zufälligen Werten für Mittelpunkt, Radius 
        // (mindestens 10 Pixel) und Farbe, der komplett zu sehen ist.
        int x = _random.Next(0, _canvas.Width);
        int y = _random.Next(0, _canvas.Height);
        int radius = _random.Next(10, Math.Max(11, Math.Min(Math.Min(_canvas.Width - x, x),
            Math.Min(_canvas.Height - y, y))));
        Pen p = new Pen(Color.FromArgb(_random.Next(0, 256), _random.Next(0, 256), _random.Next(0, 256)), 1);
        _graphicObjects.Add(new MyCircle(p, new Point(x, y), radius));
        this.Invalidate();
    }

    void AddLine(object sender, EventArgs e) {
        // Erstellt eine Linie mit zufälligen Werten für Start-, Endpunkt und
        // Farbe, die komplett zu sehen ist.
        int x1 = _random.Next(0, _canvas.Width);
        int x2 = _random.Next(0, _canvas.Width);
        int y1 = _random.Next(0, _canvas.Height);
        int y2 = _random.Next(0, _canvas.Height);
        Pen p = new Pen(Color.FromArgb(_random.Next(0, 256), _random.Next(0, 256), _random.Next(0, 256)), 1);
        _graphicObjects.Add(new MyLine(p, new Point(x1, y1), new Point(x2, y2)));
        this.Invalidate();
    }

    void AddRectangle(object sender, EventArgs e) {
        // Erstellt ein Rechteck mit zufälligen Werten für Position, Breite/Höhe 
        // (mindestens 15 Pixel) und Farbe, das komplett zu sehen ist.
        int x = _random.Next(0, _canvas.Width);
        int y = _random.Next(0, _canvas.Height);
        int w = _random.Next(15, Math.Max(16, _canvas.Width - x));
        int h = _random.Next(15, Math.Max(16, _canvas.Height - x));
        Pen p = new Pen(Color.FromArgb(_random.Next(0, 256), _random.Next(0, 256), _random.Next(0, 256)), 1);
        _graphicObjects.Add(new MyRectangle(p, new Rectangle(x, y, w, h)));
        this.Invalidate();
    }

    void AddText(object sender, EventArgs e) {
        // Erstellt ein Text-Objekt mit dem eingegebenen Text und zufälligen 
        // Werten für Position und Farbe.
        if (string.IsNullOrEmpty(_txtText.Text)) return;
        int x = _random.Next(0, _canvas.Width - 30);
        int y = _random.Next(0, _canvas.Height - 30);
        int size = _random.Next(10, 75);
        Pen p = new Pen(Color.FromArgb(_random.Next(0, 256), _random.Next(0, 256), _random.Next(0, 256)), 1);
        _graphicObjects.Add(new MyText(p, _txtText.Text, FontFamily.GenericSerif, FontStyle.Regular, size, new Point(x, y)));
        this.Invalidate();
    }
}

static class Program {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());
    }
}

Thema: [Tutorial] Gezeichnete Objekte mit der Maus verschieben
Am im Forum: Artikel

Vielen Dank an die Poweruser fürs Probelesen!

In seinem Tutorial Zeichnen in Windows-Programmen (Paint/OnPaint, PictureBox) hat herbivore beschrieben, wie man in einer Windows-Anwendung zeichnen sollte.
Ich möchte das ganze jetzt weiterführen und erklären, wie man mit Hilfe der Maus gezeichnete Objekte, wie Rechtecke, Linien und Kreise, verschieben und verändern kann.
Das ganze basiert auf herbivore's Anleitung, die man also gelesen haben sollte.

Wie finde ich heraus, ob die Maus über einem gezeichneten Objekt ist?

Dafür kann man die Klasse GraphicsPath im System.Drawing.Drawing2D-Namespace verwenden. Diese speichert geometrische Figuren in Form von Linien und Kurven zwischen bestimmten Punkten.
Wir fügen der MyGraphicObject-Basisklasse eine Eigenschaft für den GraphicsPath hinzu:

GraphicsPath _path;

protected GraphicsPath Path {
    get { return _path; }
}
Mit der Methode IsOutlineVisible kann man feststellen, ob ein angegebener Punkt auf der Linie, die das Objekt umgibt, liegt, wenn man diese mit dem angegebenen Pen-Objekt gezeichnet hat.
Dazu fügen wir der Basisklasse eine Methode Hit hinzu:

public virtual bool Hit(Point pt) {
    return Path.IsOutlineVisible(pt, _pen);
}
Wenn man diese Methode so verwendet, fällt einem schnell auf, wie schwer es ist, die Maus genau so über eine Linie zu bewegen, dass Hit true zurückgibt. Deswegen behaupten wir nun die Linie mit einem dickeren Pen-Objekt gezeichnet zu haben. Dann ist der Bereich, in den man die Maus bewegen muss um true zu erhalten um einiges größer.
Für die IsOutlineVisible-Methode wird nur die Breite des angegebenen Pen-Objekts verwendet, somit ist die Farbe irrelevant. Als Breite habe ich mit dem Wert 4 ganz gute Ergebnisse erzielt. Am besten spielt man mit dem Parameter ein bisschen rum, um das gewünschte Ergebnis zu erzielen.

Pen _hitTestPen = new Pen(Brushes.Black, 4);

public virtual bool Hit(Point pt) {
    return Path.IsOutlineVisible(pt, _hitTestPen);
}
Ob ein Punkt innerhalb eines Objekts liegt, kann man mit Hilfe der IsVisible-Methode herausfinden.
Ich habe der Beispielanwendung auch eine Methode Contains hinzugefügt, diese spielt für den Rest aber keine Rolle mehr:

public virtual bool Contains(Point pt) {
    return Path.IsVisible(pt);
}
Woher bekomme ich für meine Objekte einen GraphicsPath?

Die GraphicsPath-Klasse bietet verschiedene Methoden an (beginnen alle mit "Add" , z.B. AddLine oder AddRectangle), mit denen man geometrische Objekte, z.B. Rechteck, Ellipse, zu dem Pfad hinzufügen kann.
Anstatt sich bei jedem MyGraphicObject die Daten als Koordinaten, Rectangle-Struktur oder Ähnlichem zu merken, fügt man sie zu einem GraphicsPath hinzu.
Hier z.B. die Änderung am Konstruktor von herbivore’s MyRectangle-Klasse:

public MyRectangle(Pen pen, Rectangle rect) : base (pen) {
    Path.AddRectangle(rect);
}

Ist das mit dem GraphicsPath nicht viel komplizierter?

Nein, ist es nicht. Im Gegenteil: Da man nicht mehr lauter einzelne Strukturen und Integer-Variablen braucht, um die Angaben zu den einzelnen Objekten zu speichern, geht einiges viel leichter.
Bei herbivore’s Beispielanwendung mussten noch alle Objekte die Draw-Methode der Basisklasse implementieren. Dies ist nun nicht mehr nötig, da man schon in der Basisklasse den GraphicsPath zeichnen kann:

public virtual void Draw(Graphics g) {
    g.DrawPath(_pen, _path);
}
Auch Hit und Contains können direkt in der Basisklasse implementiert werden. Das Verschieben wird auch um einiges erleichtert, da man einen GraphicsPath ganz einfach mit einer Matrix transformieren kann. So arbeitet auch die Move-Methode, die wir der Basisklasse hinzufügen:

public virtual void Move(int deltaX, int deltaY) {
    Matrix mat = new Matrix();
    mat.Translate(deltaX, deltaY);
    _path.Transform(mat);
}

Und wie kann ich jetzt ein Objekt mit der Maus verschieben?

Dazu brauchen wir folgende Maus-Ereignisse unseres Formulars: MouseDown, MouseMove und MouseUp.
Das Verschieben läuft nun wie folgt ab:
  • Im MouseDownEventHandler testen wir, ob die Maus sich auf einem Objekt befindet. Wenn ja merken wir es uns und auch die Position der Maus.
  • Im MouseMoveEventHandler prüfen wir zuerst, ob wir uns ein Objekt zum Verschieben gemerkt haben (sprich, ob wir im Moment ein Objekt verschieben wollen). Wenn dies der Fall ist, rechnen wir den Unterschied zwischen der aktuellen Maus-Position und der letzten aus und verschieben das Objekt um diese Differenz. Dann speichern wir die Maus-Position als die letzte und zum Schluss lassen wir das Formular noch neu zeichnen, damit die Änderungen auch sichtbar werden.
  • Im MouseUpEventHandler setzen wir einfach die Variable, in der wir das Objekt zum Verschieben speichern, gleich null.
Lange Rede, kurzer Sinn: Hier ist der Code dazu:

Point _lastMouseLocation;
MyGraphicObject _movingGraphicObject;

protected override void OnMouseDown(MouseEventArgs e) {
    base.OnMouseDown(e);
    // Wenn die Maus außerhalb der Zeichenfläche gedrückt wurde, wird abgebrochen.
    if (!_canvas.Contains(e.Location)) return;
    // Anderenfalls wird die Liste mit den gezeichneten Objekten von hinten (damit
    // das oberste Objekte gefunden wird) durchgegangen und geprüft, über welchem
    // Objekt die Maus sich befindet. 
    for (int i = _graphicObjects.Count - 1; i ≥ 0; i--) {
        MyGraphicObject go = _graphicObjects[i];
        if (go.Hit(e.Location)) {
            _movingGraphicObject = go;
            break;
        }
    }
    _lastMouseLocation = e.Location;
}

protected override void OnMouseMove(MouseEventArgs e) {
    base.OnMouseMove(e);
    if (_movingGraphicObject != null) {
        // Wenn gerade ein Objekt verschoben werden soll, wird die Differenz zur letzten
        // Mausposition ausgerechnet und das Objekt um diese verschoben.
        _movingGraphicObject.Move(e.X - _lastMouseLocation.X, e.Y - _lastMouseLocation.Y);
        _lastMouseLocation = e.Location;
        // Hier könnte man noch optimieren, indem man immer nur den Bereich
        // neuzeichnet, in dem das Objekt bewegt wurde.
        this.Invalidate();
    }
}

protected override void OnMouseUp(MouseEventArgs e) {
    base.OnMouseUp(e);
    _movingGraphicObject = null;
}

Funktioniert das auch für Text?

Ja. Die GraphicsPath-Klasse besitzt eine Methode AddString. Dabei wird der angegebene Text in Linien und Kurven umgewandelt, die in dem Pfad gespeichert werden. Dabei werden auch unterschiedliche Schriftarten sowie Stile (fett, kursiv, usw.) berücksichtigt.
Wir fügen dem Beispiel eine Klasse MyText hinzu. Nun müssen wir einige Implementierungen der Basisklasse verändern:
  • Draw: Bei den anderen Objekten haben wir nur die Linie gezeichnet, die das Objekt umgibt (z.B. die Kreislinie). Das kann man bei Text auch machen und bekommt dann eine Outline-Schrift. Hier wollen wir aber den Text normal (also ausgefüllt) zeichnen und verwenden daher FillPath statt DrawPath. Wenn man beides kombinieren würde, könnte man z.B. eine blau gefüllte Schrift mit einer schwarzen Umrandung zeichnen.

    public override void Draw(Graphics g) {
        g.FillPath(Pen.Brush, Path);
    }
  • Hit: Wir überfahren die Schrift nicht nur, wenn wir die Maus über die Linie bewegen, sondern auch, wenn wir uns über dem Inneren befinden. Das heißt Hit sollte nun true zurückliefern, wenn die Maus sich entweder über der Linie oder über dem Inneren befindet:

    public override bool Hit(Point pt) {
        return Contains(pt) || base.Hit(pt);
    }
Wie kann ich das Zeichnen optimieren, wenn der Bildaufbau beim Verschieben zu langsam ist?

Eine z.T. erhebliche Beschleunigung der Zeichnung lässt sich erreichen, wenn pro Zeichenvorgang nicht das gesamte Control neu gezeichnet wird, sondern nur die Bereiche, wo sich tatsächlich Zeichnungsobjekte befinden bzw. nur die Bereiche, die sich überhaupt geändert haben. Dieses Konzept wird im Snippet "Gezieltes OwnerDrawing" - schnelles Zeichnen bewegter Objekte von ErfinderDesRades umgesetzt.

Ende

Dieser Artikel zeigt eine Methode auf, mit der man mit Hilfe der Maus mit gezeichneten Objekten interagieren kann.

Wer sich weiter mit dem Thema beschäftigen möchte, sollte mal ein Blick auf folgende Diskussionen aus diesem Forum werfen:
- Linie wie bei einem Bildbearbeitungsprogramm
- DrawLine -> Enden verschieben

Thema: Gibts die Color Komponenten als Standalone?
Am im Forum: Grafik und Sound

Hallo Seikilos,

Im .NET-Framework ist nichts enthalten. Schau am besten mal bei Codeproject nach, da gibt es viele solche Komponenten, die können teiwleise auch noch um einiges mehr.

Gruß,
Thomas

Thema: Desktopbereich verkleinern
Am im Forum: GUI: Windows-Forms

Hallo okoman,

Schau dir mal Xqgene's Einfache ToolBar an. Bei der wird der Desktopbereich verkleinert.

Gruß,
Thomas