ToggleButton Zeichnet komisch Oo

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 39 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    Facebamm schrieb:

    weil ich dann die Farben für evtl. andere Projekte nicht anpassen kann
    Das kannst Du selbstverständlich auch bei einer geladenen Bitmap.
    Findest Du FloodFill. Da gibt es langsame Ausführungen in .NET, nimm mal die API-Funktion, die flutscht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Facebamm schrieb:

    größer als die Vorlage
    Oder Du machst ne neue Vorlage.
    Überleg mal, ob Du da mit ner EMF (einfache Vektorgrafik) was machen kannst.
    stackoverflow.com/questions/15…w-to-save-an-image-as-emf
    blog.davidsilvasmith.com/2008/…ting-metafile-in-net.html
    msdn.microsoft.com/de-de/libra…g.metafile(v=vs.110).aspx
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Facebamm Das Vektorbild kannst Du in Ruhe zu Hause stylen und dann den Ressourcen hinzufügen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Meiner Ansicht nach das manuelle Zeichnen. Da hast du wesentlich mehr Kontrolle über die Art der Arithmetik, bist nicht auf Ressourcen angewiesen und es ist auch der übliche Stil. Wenn du übrigens Anwendungen in eigenem Design erstellen willst, empfehle ich dir dringend WPF. Dort hast du weitaus mehr Möglichkeiten, sowas zu machen, es ist einfacher (meiner Ansicht nach), komplexe Oberflächen zu gestalten und du hast den Vorteil eines recht ausgereiften Datenbindungssystems. Man muss sich halt nur in MVVM einarbeiten und verstehen, dass die "custom controls" über Templates und dem ganzen Zeug auf den bestehenden Steuerelementen zu lösen sind, wann immer möglich (in gefühlten 95% der Fälle ist das möglich).

    Viele Grüße
    ~blaze~
    Ich würde auch Rod widersprechen und sagen, dass das selbst Zeichnen einem Bild (egal ob Raster oder Vektor) vorzuziehen ist. Damit ersparst du dir einfach weitere Variablen bei dem Prozess (wie beispielsweise eine Vektorbibliothek) und bewahrst dir jegliche Flexibilität.

    Wenn du deine Implementation noch etwas optimieren möchtest, könntest du übrigens den GraphicsPath zwischenspeichern und nur bei einem Resize neu berechnen.
    @Facebamm Probierma

    C#-Quellcode

    1. int x = ToggleState == ToggleState.On ? 4 : Width - Height + 4;
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany, ähm ja hab ich schon :D ... Das mit der Vektor-Graphik ist auf meiner ToDo list sowie der FloodFill Algo :D ... ausprobieren werde ich mal beides :D
    @~blaze~, mvvm versteh ich noch nicht ganz, bzw ich kenn so nicht mal die Grundlagen mit dem Binding :/ und deshalb mach ich es erstmal in WinFrom, wobei mir WinFrom so oder so mehr liegt.
    @nafets, Hab es mit dem zwischen speichern eingebunden :D

    Ansatz zum FloodFill algo..
    #Problem der Offset
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Drawing;
    4. using System.Drawing.Imaging;
    5. using System.Linq;
    6. using System.Runtime.InteropServices;
    7. using System.Text;
    8. using System.Threading.Tasks;
    9. namespace FaceMaterial
    10. {
    11. class FloodFill
    12. {
    13. private static byte[] Pixelbytes;
    14. private static int Offset;
    15. public static Bitmap Calc(Bitmap bmp, Point point, Color fillcolor)
    16. {
    17. #region Convert
    18. Rectangle rectangle = new Rectangle(0, 0, bmp.Width, bmp.Height);
    19. BitmapData bmpData = bmp.LockBits(rectangle, ImageLockMode.ReadWrite, bmp.PixelFormat);
    20. IntPtr intPtr = bmpData.Scan0;
    21. int bytewidth = bmpData.Stride;
    22. int bytecount = Math.Abs(bytewidth) * bmp.Height;
    23. Pixelbytes = new byte[bytecount - 1];
    24. Marshal.Copy(intPtr, Pixelbytes, 0, bytecount);
    25. int offset = Image.GetPixelFormatSize(bmp.PixelFormat);
    26. #endregion
    27. #region FloodFill
    28. //Color srcColor = null;
    29. setPixel(point.X, point.Y);
    30. void setPixel(int x, int y) //idee war das jeder Pixsel seinen nachtbarn anschaut und ihm sagt du musst dich färben und der dann wiederrum schaut
    31. {
    32. int byteX = point.X * offset;
    33. int byteY = point.X * bytewidth;
    34. int position = byteX + byteY;
    35. byte r = Pixelbytes[position];
    36. byte g = Pixelbytes[position + 1];
    37. byte b = Pixelbytes[position + 2];
    38. Color isColor = Color.FromArgb(r, g, b);
    39. // if()
    40. }
    41. #endregion
    42. #region Convert Back
    43. Marshal.Copy(Pixelbytes, 0, intPtr, Pixelbytes.Length);
    44. bmp.UnlockBits(bmpData);
    45. #endregion
    46. return bmp;
    47. }
    48. }
    49. }


    Update ToggleButton @FormFollowsFunction
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.ComponentModel;
    3. using System.Drawing;
    4. using System.Drawing.Drawing2D;
    5. using System.Windows.Forms;
    6. namespace FaceMaterial
    7. {
    8. public delegate void PropertiesChangeHandle();
    9. public class ToggleButton : Control
    10. {
    11. private bool togglestate = true;
    12. [Category("States")]
    13. public bool State
    14. {
    15. get => togglestate; set {
    16. PropertyChange(value, ref togglestate, ReCalcGraphicsPath);
    17. Toggled?.Invoke(this, null);
    18. }
    19. }
    20. private Color oncolor = Color.DodgerBlue;
    21. [Category("States")]
    22. public Color OnColor { get => oncolor; set => oncolor = PropertyChange(value); }
    23. private Color offcolor = Color.Red;
    24. [Category("States")]
    25. public Color OffColor { get => offcolor; set => offcolor = PropertyChange(value); }
    26. private Color togglecolor = Color.White;
    27. [Category("States")]
    28. public Color ToggleColor { get => togglecolor; set => togglecolor = PropertyChange(value); }
    29. public event EventHandler Toggled;
    30. public event PropertiesChangeHandle PropertiesChangeEvent;
    31. private GraphicsPath BackGraphicPath;
    32. private GraphicsPath ForeGraphicsPath;
    33. public ToggleButton()
    34. {
    35. SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
    36. DoubleBuffered = true;
    37. ResizeRedraw = true;
    38. BackColor = Color.Transparent;
    39. Resize += (sender, e) => ReCalcGraphicsPath();
    40. Paint += ToggleButton_Paint;
    41. Click += (sender, e) => State = ToggleScanner(false, true);
    42. DoubleClick += (sender, e) => State = ToggleScanner(false, true);
    43. }
    44. private T ToggleScanner<T>(T argtrue, T argfalse) => State ? argtrue : argfalse;
    45. /// Entfernt
    46. /// - Grund: BackColor = Color.Transparent;
    47. //private void SetRoundPath()
    48. //{
    49. // using (GraphicsPath graphicsPath = new GraphicsPath())
    50. // {
    51. // graphicsPath.AddArc(0, 0, Height, Height, 90, 180);
    52. // graphicsPath.AddArc(Width - Height, 0, Height, Height, 270, 180);
    53. // graphicsPath.CloseFigure();
    54. // this.Region = new Region(graphicsPath);
    55. // }
    56. //}
    57. private void ReCalcGraphicsPath()
    58. {
    59. ///Setting
    60. ///
    61. int x = ToggleScanner(4, Width - Height + 4);
    62. ///Back
    63. ///
    64. GraphicsPath backgraphicsPath = new GraphicsPath();
    65. backgraphicsPath.AddArc(0, 0, Height, Height, 90, 180);
    66. backgraphicsPath.AddArc(Width - Height, 0, Height, Height, 270, 180);
    67. backgraphicsPath.CloseFigure();
    68. BackGraphicPath = backgraphicsPath;
    69. ///Fore
    70. ///
    71. GraphicsPath foregraphicsPath = new GraphicsPath();
    72. foregraphicsPath.StartFigure();
    73. foregraphicsPath.AddArc(x, 4, Height - 8, Height - 8, 0, 360);
    74. foregraphicsPath.CloseFigure();
    75. ForeGraphicsPath = foregraphicsPath;
    76. }
    77. private void ToggleButton_Paint(object sender, PaintEventArgs e)
    78. {
    79. ///Setting
    80. ///
    81. Graphics graphics = e.Graphics;
    82. graphics.SmoothingMode = SmoothingMode.AntiAlias;
    83. graphics.CompositingQuality = CompositingQuality.HighQuality;
    84. graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
    85. graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
    86. ///back
    87. ///
    88. if (BackGraphicPath != null)
    89. graphics.FillPath(new SolidBrush(ToggleScanner(OnColor, OffColor)), BackGraphicPath);
    90. ///Fore
    91. ///
    92. if (ForeGraphicsPath != null)
    93. graphics.FillPath(new SolidBrush(ToggleColor), ForeGraphicsPath);
    94. }
    95. public T PropertyChange<T>(T value, ref T field)
    96. {
    97. field = value;
    98. PropertiesChangeEvent?.Invoke();
    99. Invalidate();
    100. return value;
    101. }
    102. public T PropertyChange<T>(T value)
    103. {
    104. PropertiesChangeEvent?.Invoke();
    105. Invalidate();
    106. return value;
    107. }
    108. public void PropertyChange<T>(T value, ref T field, Action action)
    109. {
    110. PropertiesChangeEvent?.Invoke();
    111. field = value;
    112. action();
    113. Invalidate();
    114. }
    115. }
    116. }
    Wenn du Windows Forms ohne Datenbindung machst, bist du sowieso eigentlich verloren. Außerdem ist das Thema nicht so kompliziert.

    Warum du FloodFill implementierst, verstehe ich allerdings auch nicht. Es bedeutet dir nur Aufwand und nützt dir letztenendes gar nichts.

    Auf jeden Fall: Wenn du Zeit hast und GUI machst, gibt es keinen Grund, WPF zu scheuen. Das ist weitaus mächtiger, als das veraltete Windows Forms (einzig und alleine bei der Platformunabhängigkeit könnte man da noch streiten, aber für das gibt es ja bspw. Xamarin).

    Viele Grüße
    ~blaze~
    @~blaze~
    Warum du FloodFill implementierst? ich werd es nicht einbinden, aber mal den algo geschrieben zuhaben ist bestimmt auch was :D

    Was ich weiß über MVVM ist:
    Das Model (M), hält nur die Eigenschaften vom Control wie Größe,Farbe usw.
    Das ViewModel (VM), verarbeitet die Eigenschaften und passt diese für das VM an.
    Das View (V), stellt alles dar ?

    Edit: Ich glaub das ist falsch :/
    Edit: View und VM gewechselt

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Facebamm“ ()

    Das schaust du dir am besten nochmal an.

    View ist die GUI (d.h. das, was du im Fall von WPF in XAML darstellst), das Model stellt die Daten bereit, die vom View dargestellt werden sollen und verarbeitet diese. Außerdem sendet es Informationen über Änderungen, usw. Das View Model dient der Verwaltung der Aktionen, die View-spezifisch sind. D.h. du hast ja bspw. Menüpunkte und dergleichen, die eine bestimmte Aktin durchführen; diese werden im View Model modelliert (quasi ist das View Model das Model der View, wohingegen das Model die Verarbeitung innerhalb des Programms enthält - unabhängig von der View bzw. dem gewählten View Model).

    Viele Grüße
    ~blaze~
    Ich sag jetzt einfach mal das ich Win-Form eher bevorzuge.

    Wie setze ich ein Bereich in den nur Controls zugelassen sind, also wie so ein Panel im eigenen Control, so das ich bestimmte Controls nicht wahllos setzen kann?

    lg Facebamm

    Facebamm schrieb:

    in den nur Controls zugelassen sind
    Kannst Du das mal etwas näher erläutern?
    Meinst Du ggf. so was wie ein TableLayoutPanel, da passt in jedes Sub-Panel genau ein Control (oder ein normales Panel mit mehreren anderen Controls drauf).
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Facebamm schrieb:

    dann kannst du doch keine Controls in die Titlebar setzten
    Doch, das geht.
    Allerdings kann ich Dir jetzt kein Beispiel posten, da muss ich erst mal mein Archiv durchstöbern. ;)
    Im Ernstfall machst Du .FormBorderStyle = None, musst Dich aber um das ganze Form-Zeugs selber kümmern.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich glaube, Facebamm wollte in einem zweiten Satz sagen, dass er gerne die Steuerelemente in einem Teil seines Steuerelements platzieren möchte.
    Das geht über einen eigenen ControlDesigner. Näher habe ich mich damit nicht beschäftigt, aber ich halte es auch für ein eher nicht so sinnvolles Unterfangen.

    Viele Grüße
    ~blaze~