Eingabemaske mit Zeichnung und Maßfelder aufbauen



  • Hallo,

    ich bin gerade an einem Programm, welches mir den Aufbau eines Fensters berechnen soll. Quasi Verbreiterung links, rechts, oben usw... Soweit funktioniert das alles auch wie gewünscht, keine Probleme.

    Damit das Programm arbeiten kann, werden zunächst die Fensterprofile mit ihren Maßen eingegeben. Später zur Berechnung der einzelnen Fenster dann natürlich die Fenstermaße. Die Eingabemaske beider habe ich bis jetzt nur behelfsmäßig aufgebaut: Ich zeichne in eine BMP die Umrisse des Profils/Fensters, inkl. Maßpfeile (und was sonst noch so dazu gehört) und platziere darüber Textboxen für die Eingabe der Maße. Insgesamt sind das nur ca. 10 Zeichnungen/Zeichenvarianten mit bis zu 20 Maßen. Bisher habe ich nur 2 der Eingabemasken fertig, die anderen sind eher behelfsmäßig.

    Mein "Problem": Ich habe das ganze mit "gefühlten zig tausend" new Point, Line, ... und TextBox . ... = ... usw. aufgebaut. Sprich sehr unübersichtlich und absolut änderungsUNfreundlich aufgebaut.

    Wie würdet ihr so eine Eingabemaske aufbauen?

    Die Zeichnungen sind notwendig und können nicht weggelassen werden. Klar könnte ich die Zeichnungen abspeichern und wieder aufrufen, mir gefällt aber nicht dass ich dann immer noch die Textboxen von "Hand" irgwo ohne feste Bezugspunkte ablege und bei Änderungen immer noch zu komplex/unübersichtlich wär um eben schnell mal was zu ändern. Das ganze sollte möglichst einfach und doch so flexibel wie möglich sein.

    Gruß



  • Ich würde das Fenster einfach als feste Skizze und die TextBoxes ebenfalls an fester
    Stelle platzieren.

    Wenn mit den erfolgten Eingaben auch die Darstellung der Skizze verändert werden soll, kommst du um eine
    gewisse Bitmap-Friemelei mit Graphics-Methoden nicht herum.
    Näheres siehe hier http://msdn.microsoft.com/de-de/library/system.drawing.graphics(v=vs.110).aspx

    Am besten zeigst du mal etwas Code.



  • Hier die Code-Ausschnitte

    Zeichnen einer Darstellung

    //Mauer links
    Point[] Mauer_Rechts = {new Point(iStart_links - 50 , (int)(iStart_Höhe_Querschnitt + 100 * iMaßstab)),
                            new Point(iStart_links,       (int)(iStart_Höhe_Querschnitt + 100 * iMaßstab)),
                            new Point(iStart_links,       iStart_Höhe_Querschnitt),
                            new Point((int)(iStart_links + ((kFensterdaten.iInnenmaß1 - kFensterdaten.iAußenmaß1)/2)*iMaßstab), iStart_Höhe_Querschnitt),
                            new Point((int)(iStart_links + ((kFensterdaten.iInnenmaß1 - kFensterdaten.iAußenmaß1)/2)*iMaßstab), (int)(iStart_Höhe_Querschnitt - 100 * iMaßstab)),
                            new Point(iStart_links - 50,(int)(iStart_Höhe_Querschnitt - 100 * iMaßstab))};
    Graphics.FromImage(bmFenster).DrawLines(penBlack, Mauer_Rechts);
    
    //Fenster-Querschnitt zeichnen
    iStart_links += (int)(kFensterdaten.iFensterluft * iMaßstab);
    
    //Verbreiterungen links
    foreach (Verbreiterungen k in kFensterdaten.LVerbreiterungen_verbaut)
    {
        Graphics.FromImage(bmFenster).DrawRectangle(penBlack, iStart_links, iStart_Höhe_Querschnitt, int.Parse(k.sBreite) * iMaßstab, iRahmentiefe);
        iStart_links += (int)(int.Parse(k.sBreite) * iMaßstab);
    }
    //Fenster (Rahmen)
    Graphics.FromImage(bmFenster).DrawRectangle(penBlack, iStart_links, iStart_Höhe_Querschnitt, (int)(int.Parse(kFensterdaten.Rahmendaten.sRahmenbreite_außen) * iMaßstab), iRahmentiefe);
    
    Graphics.FromImage(bmFenster).DrawRectangle(penBlack, iStart_links, iStart_Höhe_Querschnitt, kFensterdaten.iFensterbreite * iMaßstab, iRahmentiefe);
    iStart_links += (int)(kFensterdaten.iFensterbreite * iMaßstab);
    
    Graphics.FromImage(bmFenster).DrawRectangle(penBlack, iStart_links - (int)(int.Parse(kFensterdaten.Rahmendaten.sRahmenbreite_außen) * iMaßstab), 
    iStart_Höhe_Querschnitt, (int)(int.Parse(kFensterdaten.Rahmendaten.sRahmenbreite_außen) * iMaßstab), iRahmentiefe);
    
    //Verbreiterungen links
    foreach (Verbreiterungen k in kFensterdaten.LVerbreiterungen_verbaut)
    {
        Graphics.FromImage(bmFenster).DrawRectangle(penBlack, iStart_links, iStart_Höhe_Querschnitt, int.Parse(k.sBreite) * iMaßstab, iRahmentiefe);
        iStart_links += (int)(int.Parse(k.sBreite) * iMaßstab);
    }
    iStart_links += (int)(kFensterdaten.iFensterluft * iMaßstab);
    iStart_rechts = iStart_links;
    
    //Mauer rechts
    Point[] Mauer_links = {new Point(iStart_links + 50 , (int)(iStart_Höhe_Querschnitt + 100 * iMaßstab)),
                           new Point(iStart_links,       (int)(iStart_Höhe_Querschnitt + 100 * iMaßstab)),
                           new Point(iStart_links,       iStart_Höhe_Querschnitt),
                           new Point((int)(iStart_links - ((kFensterdaten.iInnenmaß1 - kFensterdaten.iAußenmaß1)/2)*iMaßstab), iStart_Höhe_Querschnitt),
                           new Point((int)(iStart_links - ((kFensterdaten.iInnenmaß1 - kFensterdaten.iAußenmaß1)/2)*iMaßstab), (int)(iStart_Höhe_Querschnitt - 100 * iMaßstab)),
                           new Point(iStart_links + 50,(int)(iStart_Höhe_Querschnitt - 100 * iMaßstab))};
    Graphics.FromImage(bmFenster).DrawLines(penBlack, Mauer_links);
    
    Fenster.Image = bmFenster;
    

    Zeichnen von Maßpfeilen

    //Maßpfeil oben, Außenmaß1
    pStart.X = ixMauer_links_Start1 + iTiefe_Mauer / 2;
    pStart.Y = iy + iheight - iTiefe_Mauer - iMaßhöhe_außen2 + iHohe_TextBox / 2;
    pEnde.X = ixMauer_rechts_Start1 - iTiefe_Mauer / 2;
    pEnde.Y = pStart.Y;
    gphView.DrawLine(new Pen(Color.Black), pStart, pEnde);
    Maßpfeil_zeichnen(pStart, "links");
    Maßpfeil_zeichnen(pEnde, "rechts");
    
    //Maßpfeil oben, Außenmaß2_1
    pStart.X = ixMauer_links_Start1 + iTiefe_Mauer / 2;
    pStart.Y = iy + iheight - iTiefe_Mauer - iMaßhöhe_außen1 + iHohe_TextBox / 2;
    pEnde.X = ixMauer_links_Start2 + iTiefe_Mauer / 2;
    pEnde.Y = pStart.Y;
    gphView.DrawLine(new Pen(Color.Black), pStart, pEnde);
    Maßpfeil_zeichnen(pEnde, "rechts");
    

    Anordnung der Textboxen zur Maßeingabe

    tbAußenmaß1.Visible = true;
    tbInnenmaß1.Visible = true;
    tbRollladenlichtmaß1.Visible = true;
    tbRollladenlichtmaß2_1.Visible = true;
    tbRollladenlichtmaß2_2.Visible = true;
    tbRollladenlichtmaß2_3.Visible = true;
    tbAußenmaß2_1.Visible = true;
    tbAußenmaß2_2.Visible = true;
    tbInnenmaß2_1.Visible = true;
    tbInnenmaß2_2.Visible = true;
    
    tbAußenmaß1.Location = new Point((int)ix + iwidth / 2 - tbAußenmaß1.Width / 2, iy + iheight - iTiefe_Mauer - iMaßhöhe_außen2);
    tbAußenmaß2_1.Location = new Point((int)ix + iwidth / 2 - iBreite_Fenster / 2 - tbAußenmaß1.Width / 2, iy + iheight - iTiefe_Mauer - iMaßhöhe_außen1);
    tbAußenmaß2_2.Location = new Point((int)ix + iwidth / 2 + iBreite_Fenster / 2 - tbAußenmaß1.Width / 2, iy + iheight - iTiefe_Mauer - iMaßhöhe_außen1);
    
    tbRollladenlichtmaß1.Location = new Point((int)ix + iwidth / 2 - tbAußenmaß1.Width / 2, iy + iheight - iTiefe_Mauer + iMaßhöhe_mitte1);
    tbRollladenlichtmaß2_1.Location = new Point((int)ix + iwidth / 2 - iBreite_Fenster / 2 - tbAußenmaß1.Width / 2, iy + iheight - iTiefe_Mauer + iMaßhöhe_mitte2);
    tbRollladenlichtmaß2_2.Location = new Point((int)ix + iwidth / 2 - tbAußenmaß1.Width / 2 + iTiefe_Mauer / 4, iy + iheight - iTiefe_Mauer + iMaßhöhe_mitte2);
    tbRollladenlichtmaß2_3.Location = new Point((int)ix + iwidth / 2 + iBreite_Fenster / 2 - tbAußenmaß1.Width / 2, iy + iheight - iTiefe_Mauer + iMaßhöhe_mitte2);
    
    tbInnenmaß1.Location = new Point((int)ix + iwidth / 2 - tbAußenmaß1.Width / 2, iy + iheight + iMaßhöhe_innen2);
    tbInnenmaß2_1.Location = new Point((int)ix + iwidth / 2 - iBreite_Fenster / 2 - tbAußenmaß1.Width / 2, iy + iheight + iMaßhöhe_innen1);
    tbInnenmaß2_2.Location = new Point((int)ix + iwidth / 2 + iBreite_Fenster / 2 - tbAußenmaß1.Width / 2, iy + iheight + iMaßhöhe_innen1);
    

    Das sind nur kleine Ausschnitte, die immer noch am wachsen sind.



  • Genauso hatte ich die Friemelei erwartet. Vielleicht könnte man mit einem Panel um das Bitmap einiges erleichtern?
    Man ändert dann evtl. nur die Abmessungen des Panels und erschlägt damit einige Positionierungen.
    Bleibt aber vom Design der Eingabemaske abhängig.



  • Ein Panel hört sich gar nicht so schlecht an. Ob ich es so machen werde weiß ich noch nicht, es bleibt aber auf jeden Fall mal im Hinterkopf.

    Gibt es sonst noch Vorschläge/Anmerkungen?



  • Schau Dir mal das TableLayoutPanel an. Du hast schon ganz recht, dass der Code bisher sehr "änderungsUNfreundlich" ist und Dir in Zukunft Kopfschmerzen bereiten wird.
    Kannst Du mal einen Screenshot der bisherigen GUI zeigen? Dann kann man evtl besser helfen, wenn zu sehen ist was genau erreicht werden soll.

    Übrigens, Dein Code erzeugt massenhaft Ressourcen-Leaks. Bei Objekten die das IDisposable-Interface implementieren sollte man direkt oder indirekt die Dispose-Methode aufrufen. Momentan verlässt Du Dich darauf, dass die Finalizer-Methoden alle Ressourcen freigeben, was auch durchaus lange gut gehen kann. Dummerweise ist der Zeitpunkt, zudem der Garbage-Collector die Finalizer-Methode von unreferenzierten Objekten aufruft undefiniert und nicht-deterministisch.

    Konkret:

    Graphics.FromImage(bmFenster).DrawLines(penBlack, Mauer_Rechts);
    

    ➡

    using(var g = Graphics.FromImage(bmFenster))
     g.DrawLines(penBlack, Mauer_Rechts);
    


  • Ok, das war mir nicht klar, werde das ändern.

    So sieht eine Maske aus:
    http://img5.fotos-hochladen.net/uploads/eingabemaskes63y9cv7kb.jpg



  • Also, diese Maske ist Deine Vorlage und die Zeichnung baust Du mühselig mit der Graphics-Klasse nach. Richtig?

    Kannst Du nicht einfach die Zeichnung in korrekter Auflösung direkt als Hintergrundbild verwenden? Oder sind da Animationen vorgesehen?
    Dein Argument dagegen war ja:

    neo47 schrieb:

    Klar könnte ich die Zeichnungen abspeichern und wieder aufrufen, mir gefällt aber nicht dass ich dann immer noch die Textboxen von "Hand" irgwo ohne feste Bezugspunkte ablege und bei Änderungen immer noch zu komplex/unübersichtlich wär um eben schnell mal was zu ändern. Das ganze sollte möglichst einfach und doch so flexibel wie möglich sein.

    Nun könntest Du auf den Maskenbildern die Textboxen durch eindeutige Farben markieren. Dein Programm analysiert die Bilder am anfang, sucht nach Rechtecken mit bestimmten Farbcodes und platziert dort die jeweilige Textbox.



  • Nein Animationen sind nicht vorgesehen.

    Die Herangehensweise find ich interessant, das könnte funktionieren. Mal sehen ob ich das umsetzten kann.


Anmelden zum Antworten