Autor Beitrag
McFlayr
Hält's aus hier
Beiträge: 13



BeitragVerfasst: Di 30.08.16 12:26 
Hallo Community,

ich bin gerade ein wenig am verzweifeln und hoffe das mir hier jemand helfen kann.
Folgendes Problem:
Ich will ein eigenes Steuerelement, abgeleitet von einem TableLayoutPanel, basteln.
Dabei soll per Klick, die Zelle, auf der sich der Mauszeiger befindet, eingefärbt werden.
Soweit funktioniert das auch.
Nun will ich allerding nicht jede Zelle einzeln anklicken müssen sonder auch wenn ich mit der Maus über weitere Zellen fahre, sollen diese eingefärbt werden.

Meine bisherige Lösung (siehe unten) geht schon in die richtige Richtung aber wenn ich die Maus etwas zu schnell bewege werden nicht alle Zellen eingefärbt.


ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace test2
{
    public partial class zeichenPanel : TableLayoutPanel
    {
        Rectangle clicked = new Rectangle();
        bool wasClick = false;

        public zeichenPanel()
        {
            this.MouseDown += drawPanel_MouseDown;
            this.MouseUp += drawPanel_MouseUp;
            this.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single;
            this.Paint += drawPanel_Paint;
            this.MouseMove += drawPanel_MouseMove;
        }

        private void drawPanel_MouseDown(object sender, MouseEventArgs e)
        {
            int row = 0;
            int verticalOffset = 0;
            int clickx = e.X;
            int clicky = e.Y;
            foreach (int h in this.GetRowHeights())
            {
                int column = 0;
                int horizontalOffset = 0;
                foreach (int w in this.GetColumnWidths())
                {
                    Rectangle rectangle = new Rectangle(horizontalOffset, verticalOffset, w, h);
                    if (rectangle.Contains(e.Location))
                    {
                        clicked = rectangle;
                        wasClick = true;
                        this.Invalidate(rectangle);
                        return;
                    }
                    horizontalOffset += w;
                    column++;
                }
                verticalOffset += h;
                row++;
            }
        }
        private void drawPanel_MouseMove(object sender, MouseEventArgs e)
        {
            if (wasClick)
            {
                int row = 0;
                int verticalOffset = 0;
                int clickx = e.X;
                int clicky = e.Y;
                foreach (int h in this.GetRowHeights())
                {
                    int column = 0;
                    int horizontalOffset = 0;
                    foreach (int w in this.GetColumnWidths())
                    {
                        Rectangle rectangle = new Rectangle(horizontalOffset, verticalOffset, w, h);
                        if (rectangle.Contains(e.Location))
                        {
                            clicked = rectangle;
                            wasClick = true;
                            this.Invalidate(rectangle);
                            return;
                        }
                        horizontalOffset += w;
                        column++;
                    }
                    verticalOffset += h;
                    row++;
                }
            }          
        }

        void drawPanel_MouseUp(object sender, MouseEventArgs e)
        {
            wasClick = false;
        }

        private void drawPanel_Paint(object sender, PaintEventArgs e)
        {
            if (wasClick)
            {
                Graphics g = e.Graphics;
                Rectangle r = clicked;
                g.FillRectangle(Brushes.Red, r);
                //wasClick = false;
            }
        }
    }
}


Vielleicht hat noch jemand eine besser Idee, anstatt dies mit einem TableLayoutPanel zu realisieren.

Vielen Dank im Voraus
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Di 30.08.16 14:28 
Hallo und :welcome:

beim MouseMove wird nicht für jeden Pixel das Ereignis ausgelöst, sondern nur innerhalb bestimmter Intervalle, so daß bei schnellen Bewegungen einige Pixel übersprungen werden.

Merke dir einfach im MouseDown und MouseMove den letzten Positionswert (e.X, e.y) und führe dann in einer Schleife von diesem Wert bis zur aktuellen Position die Berechnung durch (mit entsprechend logischer Schrittweite).

Und lege unbedingt eine eigene Methode für den gleichen Code innerhalb der MouseDown- und MouseMove-Methode an!
McFlayr Threadstarter
Hält's aus hier
Beiträge: 13



BeitragVerfasst: Di 30.08.16 15:14 
Danke für deine Antwort.

Die Methode habe ich schon mal angelegt.

Könntest du mir dein Vorgehen noch etwas genauer beschreiben. Ich stehe gerade echt auf dem Schlauch. :?

Vielen Dank im Voraus
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 30.08.16 15:30 
Das wird ohne weitere Vorkehrungen nicht so einfach funktionieren wie user profile iconTh69 das beschreibt.
Beispiele:
Man verlässt das Control an einem Rand und betritt das Control wieder an einem Rand. Die Maus ist jetzt woanders über dem Control aber hat den Weg dazwischen nicht wirklich zurückgelegt.
Oder ich minimiere die Form(per Keyboard shortcut) verschiebe die Maus und maximiere die Form wieder. Ich bin wieder mit der Maus woanders übert dem Control ohne den Weg dazwischen zurückgelegt zu haben.
Oder ein Stück Software setzt die Maus explizit auf eine bestimmte Position ohne ~Bewegung~ (es gibt unendliche viele Scripts, Programme die das tun) zwischen Quell und Zielpunkt.

Darum wäre erstmal zu klären warum
Zitat:
Meine bisherige Lösung (siehe unten) geht schon in die richtige Richtung aber wenn ich die Maus etwas zu schnell bewege werden nicht alle Zellen eingefärbt.

das schlimm ist. Das Verhalten ist für mich fast systemimmanent und nicht wirklich umgehbar. Warum ist das den ein TableLayoutPanel und nicht einfach irgendein Control dessen Fläche man selbst in Zellen einteilt? Brauchst du irgendwas vom TableLayoutPanel?
McFlayr Threadstarter
Hält's aus hier
Beiträge: 13



BeitragVerfasst: Di 30.08.16 15:47 
Hallo Ralf,

das tlp habe ich gewählt weil mir das auf Anhieb am einfachsten vorkam. Da konnte ich das Raster definieren und die Zellen färben.
Ich habe auch probiert ein normales PAnel zu nehmen und habe darauf mein Raster gezeichnet aber da liesen sich die Zellen nicht so "einfach" ansprechen.

Mein Ziel ist es in einem Raster die Zellen per Mausklick zu färben(das natürlich auch beim ziehen mit gedrückter Maustaste).

Hast du da eine bessere Idee als das mit einem tlp zu realisieren?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 30.08.16 16:17 
Ich würde das immer noch mit einem Panel machen.

Beispiel im Anhang. Ich habe auch mal user profile iconTh69 Idee implementiert. Setzte mal die TryToBeSmart Property im Grid und schau was passiert wenn du die von mir beschriebenen Dinge ausprobierst ob dir das so noch ~schmeckt~ ;)

Edit: Zip aktualisiert. FollowOnlyWhenMousePressed ergänzt für "einfärben nur wenn Maustaste gedrückt"
Einloggen, um Attachments anzusehen!
McFlayr Threadstarter
Hält's aus hier
Beiträge: 13



BeitragVerfasst: Mi 31.08.16 13:32 
Vielen Dank Ralf,

das hat mir schon sehr geholfen. Jetzt versuche ich mich daran das ganze noch mehrfarbig zu gestalten und alle gefüllten Kästchen wieder zu leeren. Mal schauen ob ich das hinbekomme :D

Ich danke dir auf jeden Fall schon mal sehr!
McFlayr Threadstarter
Hält's aus hier
Beiträge: 13



BeitragVerfasst: Do 08.09.16 12:17 
Hier bin ich wieder^^ mit dem nächsten Problem.

Wenn ich jetzt auf einem Panel, wie beispielsweise das von Ralf, gezeichnet habe und ich habe eventuell noch weitere Objekte zum Panel hinzugefügt, wie PicturBoxen oder so, welche Möglichkeiten habe ich das zu speichern und zu laden.

Ich möchte den Zustand des Panels mit seinen "Child"-Elementen in eine Datei speichern und diese später laden können.
Mein erster Gedanke war alle Objekteigenschaften in einer Datei zu speichern und beim laden neue Objekte mit den gespeicherten Eigenschaften zu erstellen.

Hat jemand eine Idee, dies eleganter zu realisieren?

Vielen Dank im Voraus!