Laden...

Wie Instanzvariable einer Klasse aus einer protected Funktion heraus befüllen? [==> einfach setzen]

Erstellt von JanLehmL vor 9 Jahren Letzter Beitrag vor 9 Jahren 1.899 Views
J
JanLehmL Themenstarter:in
5 Beiträge seit 2014
vor 9 Jahren
Wie Instanzvariable einer Klasse aus einer protected Funktion heraus befüllen? [==> einfach setzen]

Hallo,

kurz und hoffentlich knapp mein Problem:
Ich muss aus einer onPaint Methode eine globale Variable dessen Klasse befüllen.
Nur leider ist die überschriebe OnPaint-Methode "protected" was mir dieses nicht erlaubt 😦
Wie kann ich vorgehen um mein Vorhaben umzusetzen?


public class
{
     int breite;
     //...
     protected override OnPaint(PaintEvent e)
     { 
          //...
          breite = 1;
     }
     
     public void messageBreite()
     {
          MessageBox.Show(breite.toString()); <- Ergebnis = 0;
     }
}

Hier der komplette Code mit übersicht mit MessageBoxen um zu kennzeichnen, wann ich die richtigen Werte erwarte.


public class Graphicpanel : Panel
    {
        private static int radius = 10;

        private Color backgroundColor;
        private Color borderColor;
        private int edgeWidth;
        private Pen pen;
        private SolidBrush solidBrush;
        private GraphicsPath graphicsPath;
        private Graphics graphics;
        
        private UnclickableLabel[] unclickableLabel;
        private int width;
        private int height;

        public Graphicpanel(Color backgroundColor, Color borderColor, int edgeWidth)
        {
            this.backgroundColor = backgroundColor;
            this.borderColor = borderColor;
            this.edgeWidth = edgeWidth;
            this.pen = new Pen(this.borderColor, this.edgeWidth);
            this.solidBrush = new SolidBrush(this.backgroundColor);
            unclickableLabel = new UnclickableLabel[16];

            this.Dock = DockStyle.Fill;
            this.BorderStyle = System.Windows.Forms.BorderStyle.None;
            this.AutoSize = true;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            int x = edgeWidth;
            int y = edgeWidth;
            width = Width - (x * 2);
            height = Height - (y * 2);

            MessageBox.Show(this.Width.ToString()); //Ergebnis: 144 <-- Korrekt!
            MessageBox.Show(this.width.ToString()); //Ergebnis: 140 <-- Korrekt!

            graphicsPath = new GraphicsPath();
            graphics = e.Graphics;
            graphicsPath.AddLine(x + radius, y, x + width - (radius * 2), y);
            graphicsPath.AddArc(x + width - (radius * 2), y, radius * 2, radius * 2, 270, 90);
            graphicsPath.AddLine(x + width, y + radius, x + width, y + Height - (radius * 2));
            graphicsPath.AddArc(x + width - (radius * 2), y + height - (radius * 2), radius * 2, radius * 2, 0, 90);
            graphicsPath.AddLine(x + width - (radius * 2), y + height, x + radius, y + height);
            graphicsPath.AddArc(x, y + height - (radius * 2), radius * 2, radius * 2, 90, 90);
            graphicsPath.AddLine(x, y + height - (radius * 2), x, y + radius);
            graphicsPath.AddArc(x, y, radius * 2, radius * 2, 180, 90);
            graphicsPath.CloseFigure();
            graphics.DrawPath(pen, graphicsPath);
            graphics.FillPath(solidBrush, graphicsPath);
            graphicsPath.Dispose();
        }

        public void messageTheWidth()
        {
            MessageBox.Show(this.Width.ToString()); //Ergebnis: 200 <-- Nicht korrekt!
            MessageBox.Show(this.width.ToString()); //Ergebnis: 200 <-- Nicht korrekt!
        }
        
    }

Gruß
Jan

F
10.010 Beiträge seit 2004
vor 9 Jahren

Nein, das MessageBox.Show im Onpaint kann nicht funktionieren.
Dies wird nämlich auch in der Nachrichtenschleife aufgerufen und z.b. bei der Initialisierung erst mal mit der MinSize.
Danach wird resized und dann erst gilt die richtige grösse.

Und natürlich kannst du aus einer Protected funktion auf die Private variablen des selben Objekts zugreifen.

J
JanLehmL Themenstarter:in
5 Beiträge seit 2014
vor 9 Jahren

Nein, das MessageBox.Show im Onpaint kann nicht funktionieren.

Ich bekomme "nur" in der MessageBox im OnPaint-Event die richtige "Width"

Dies wird nämlich auch in der Nachrichtenschleife aufgerufen und z.b. bei der Initialisierung erst mal mit der MinSize.
Danach wird resized und dann erst gilt die richtige grösse. verstehe ich nicht

Und natürlich kannst du aus einer Protected funktion auf die Private variablen des selben Objekts zugreifen.

Ich kann aber nicht von der protected Funktion aus eine Globale Variable füllen. <- Das ist leider mein Problem.

Gruß
Jan

1.378 Beiträge seit 2006
vor 9 Jahren

Hallo JanLehmL,

im OnPaint die MessageBox aufzurufen (selbst für Debuggingzwecke) tut weh anzusehen^^. Du kannst ja auch mit Debug.WriteLine zB die Werte in die Console rausschreiben.

Wofür brauchst du denn die gespeicherten Werte überhaupt? Reichts nicht, wenn du die Breite und Höhe wie im OnPaint on-the-fly berechnest?

Und wenn Control.Width bei dir 200 anzeigt heißt dass, dass das Control 200 breit ist. Hier ist kann nichts falsch sein außer dein Control wurde fälschlicherweise resized.

Ich kann aber nicht von der protected Funktion aus eine Globale Variable füllen. <- Das ist leider mein Problem.

Die Variable wird auf jeden Fall gesetzt. Zwei Möglichkeiten für dein Problem gibt es:

  1. Die Variablen und die ControlSize wird von einer anderen Stelle zwischen OnPaint aufruf und messageTheWidth verändert. (unwahrscheinlich)

  2. Du hast unabsichtlich zwei Graphicpanels instantiiert die du fälschlicherweise für das Selbe haltest. D.h. in einem setzt du im OnPaint die Breite/Höhe und im Anderen schaust du den Wert nach.
    Um herauszufinden ob es sich um das gleiche oder unterschiedliche Panels handelt kannst du zB im OnPaint und in messageTheWidth zusätzlich "this.GetHashCode()" ausgeben und die Werte vergleichen. Wenn sich der Wert ändert, hast du mehrere Objekte angelegt oder in Verwendung.

Lg, XXX

J
JanLehmL Themenstarter:in
5 Beiträge seit 2014
vor 9 Jahren

Hallo,

es handelt sich hierbei um eine Klassenbibliothek die ich in Dynamics NAV 2009 R2 einbinde.

Hierbei habe ich eine Klasse TableLayoutPanel deren ich mehrere GraphicPanels (Panel) zuweise.

Da das TableLaPa durch einen DockStyle Top in der Breite immer anpasst möchte ich im OnPaint des GraphicPanel immer die aktuelle breite für die Zelle berechnen <-- Dieses funktioniert problemlos. Die aktuelle Breite ist allerdings nur notwendig um im GraphicPanel mehrere Labels darzustellen die ich dann anhand der Breite mittig hinzufügen kann.

Gruß
Jan

P
660 Beiträge seit 2008
vor 9 Jahren

Also ich verstehe nicht ganz das Problem, aber du müsstest in der Lage sein auf das Feld mittels Reflection zuzugreifen.
(vorrausgesetzt du Weisst wie das Feld heisst)

MfG
ProGamer*Der Sinn Des Lebens Ist Es, Den Sinn Des Lebens Zu Finden! *"Wenn Unrecht zu Recht wird dann wird Widerstand zur Pflicht." *"Ignorance simplifies ANY problem." *"Stoppt die Piraterie der Musikindustrie"

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo JanLehmL,

du hast hier definitiv ein anderes Problem.

Natürlich kann man eine Membervariable (auch Instanzvariable genannt; um eine solche handelt es sich hier, nicht um eine globale Variable ==> Titel geändert) aus einer beliebigen Methode der Klasse setzen und zwar vollkommenen unabhängig von den Zugrifsmodifiern (private, protected, public) von Methode und Variable. Also auch, wenn wie in deinem Beispiel die Variable private und die Methode protected ist.

Das ist elementares Grundlagenwissen, das man auf keinen Fall in Frage stellen sollte, selbst wenn es in einem Programm Effekte gibt, die man sich nicht erklären kann.

Bitte beachte daher, auch bei etwaigen Nachfragen [Hinweis] Wie poste ich richtig? Punkt 1.1.1.

Hier noch der Beweis:


using System;
using System.Windows.Forms;

public class MyWindow : Form
{
   int width = 0;

   public MyWindow ()
   {
      Text = "MyWindow";
      {
         var ctrlCurr = new Button ();
         ctrlCurr.Dock = DockStyle.Fill;
         ctrlCurr.Text = "Do";
         ctrlCurr.Click += DoClick;
         Controls.Add (ctrlCurr);
      }
   }

   protected override void OnPaint(PaintEventArgs e)
   {
      width = 1;
   }

   protected void DoClick (Object sender, EventArgs e)
   {
      MessageBox.Show(width.ToString());

   }
}

public static class App
{
   public static void Main ()
   {
      Application.Run (new MyWindow ());
   }
}

In der MessageBox erscheint 1. Und das würde natürlich genauso funktionieren, wenn der Code in einer eigenen Panel-Klasse stehen würde.

Wie gesagt sollte man statt der MessageBox zur Vermeidung von Problemen mit der sich ändernden Event-Reihenfolge besser Debug.WriteLine oder in einem Testprogramm sogar einfach Console.WriteLine verwenden.

Was nun genau dein Problem ist, kann ich nicht nachvollziehen. Wir sollten aber bitte festhalten, dass das Setzen einer Instanzvariable in einer (protected) Methode auf jeden Fall möglich ist.

Wenn du die Variable an einer Stelle setzt und zu einem späteren Zeitpunkt abfragst, dann muss sie den gesetzten Wert haben, wenn ...

  • das Setzen tatsächlich ausgeführt wurde und
  • die Variable in der Zwischenzeit nicht überschrieben wurde und
  • es sich bei jedem der Schritte um dasselbe und nicht etwa ein anders Objekt handelt.

Ein Zugriff per Reflection wäre zwar möglich, ist hier aber natürlich überhaupt nicht erforderlich.

herbivore

T
708 Beiträge seit 2008
vor 9 Jahren

Wenn ich Dein Ziel korrekt verstehe, weißt Du anfangs nicht wie groß Dein Panel sein wird.
Das möchtest Du im OnPaint herausfinden und speichern, welche Größe Du zur Verfügung hast und entsprechend viele Label anzeigen?
Warum abonnierst/überschreibst Du nicht das Resize- oder Scale-Event des Panels?
Diese werden aufgerufen, sobald sich die Größe des Controls verändert...

P
660 Beiträge seit 2008
vor 9 Jahren

Wenn es so ist wie trib es sagt, dann verwende ein flowlayoutpanel

MfG
ProGamer*Der Sinn Des Lebens Ist Es, Den Sinn Des Lebens Zu Finden! *"Wenn Unrecht zu Recht wird dann wird Widerstand zur Pflicht." *"Ignorance simplifies ANY problem." *"Stoppt die Piraterie der Musikindustrie"

1.378 Beiträge seit 2006
vor 9 Jahren

Hallo ProGamer,

wie soll ein FlowLayoutPanel helfen um die Veränderung der Größe des Controls mitzubekommen? Er verwendet ja bereits ein TableLayoutPanel um seine Controls zu organisieren.

Um die Größenveränderung in einem Control mitzubekommen gibt es Events:

Lg, XXX

J
JanLehmL Themenstarter:in
5 Beiträge seit 2014
vor 9 Jahren

Dankescön an alle für die Tipps & Tricks!

Das mit dem FlowLayoutPanel ist eine sehr gute Idee die ich jetzt erstmal umsetzen werde.

Gruß
Jan

Gruß
Jan