Das nervige Bauen des GUI...



  • Bei mir geht das eigentlich immer recht schnell :p Gut, kommt drauf an, wie komplex das Ganze wird, aber für nen kleinen Dialog brauch ich idR nur ~3 Minuten.
    Allerdings mache ich auch ein bisschen Vorarbeit, also zeichne mir den Dialog grob und schreibe Kommentar-mäßig auf, was bei welcher Aktion gemacht werden soll. Dann brauche ich nur zusammenzuklicken, die entsprechenden Nachrichten abzufangen und da meine Kommentare reinzuschreiben.
    Wenn ich damit zufrieden bin, mache ich bei den Dialog-Elementen pixelweise Feinjustierung und code die Kommentare aus. Das war's dann 🙂



  • Klick dir die GUI mit nem RAD Editor zu sammen.
    Für einige Sachen kann man auch mit Templates arbeiten, z.B. wenn man Membervariablen bearbeiten will.



  • warum sollte die GUI auch schneller gehen? Sie ist auch mindestens genauso wichtig wie die Programmlogik.
    Die Programmlogik interessiert einen Nutzer nicht. Ihm interessiert die GUI. Und wenn ihm die nicht passt, bringt die beste Logik nichts.

    Ich arbeite mit Qt. Der Qt-GUI-Editor ist zwar komfortabel, aber einfache GUIs entwerfe ich direkt im Code... ist da unter Umständen auch schneller



  • zwutz schrieb:

    warum sollte die GUI auch schneller gehen? Sie ist auch mindestens genauso wichtig wie die Programmlogik.
    Die Programmlogik interessiert einen Nutzer nicht. Ihm interessiert die GUI. Und wenn ihm die nicht passt, bringt die beste Logik nichts.

    was werden denn hier für verschärfte klicki-bunti argumente gebracht?^^ 🙄
    übrigens; das bauen einer schicken GUI ist eher aufgabe eines designers, weniger die eines programmierers.
    🙂



  • Maxi schrieb:

    Gibts da irgendwelche Tipps, wie man das beschleunigen kann? wie macht ihr das? ich hab nie lust auf das GUI, aber das muss eben auch sein (für unversierte benutzer). Gibts irgendwelche vorgehensmodelle oder sowas?

    Bitte nicht mit .NET anfangen, will bei native c++ bleiben, soll auch unter linux laufen 🙂

    Ok, aber ich fang mit Java an. 😉 Ich habe mir ein kleines Framework geschrieben, das mir für meinen Code automatisch die passende Eingabemaske generiert. Dafür stecke ich dann ein paar Zusatzinformationen in den Code rein, damit das Framework auch was vernünftiges generieren kann. Das sieht dann zum Beispiel so aus:

    package jaradap.model.generator;
    
    import controller.DataGenerator;
    import controller.MenuStructure;
    import controller.Name;
    import controller.descriptor.IntBounds;
    import jaradap.model.data.ThreeDimFloatRaster;
    import jaradap.model.data.ThreeDimUByteRaster;
    
    /**
     *
     * @author gregor
     */
    @Name("Hydrogen Generator")
    @MenuStructure({"Generate","Generate Hydrogen"})
    public class HydrogenGenerator implements DataGenerator<ThreeDimUByteRaster>
    {
       private final int n;
       private final int l;
       private final int m;
       private final int Z;
       private final int size;
    
       /** Creates a new instance of HydrogenGenerator */
       @Name("Default Construction")
       public HydrogenGenerator
          (
             @Name("Hauptquantenzahl n") @IntBounds(min=1,defaultValue=1,max=10) final int n,
             @Name("Drehimpulsquantenzahl l") @IntBounds(min=0,defaultValue=0,max=10) final int l,
             @Name("Magnetische Quantenzahl m") @IntBounds(min=-10,defaultValue=0,max=10) final int m,
             @Name("Kernladungszahl Z") @IntBounds(min=1,defaultValue=1,max=10) final int Z,
             @Name("Größe des Bereichs in a0") @IntBounds(min=1,defaultValue=15,max=45) final int size
          )
       {
          this.m = m;
          this.l = (Math.abs(m)>l) ? Math.abs(m) : l;
          this.n = (l > n-1) ? l+1 : n;
          this.Z = Z;
          if(this.l != l) System.out.println("l wurde korrigiert.");
          if(this.n != n) System.out.println("n wurde korrigiert.");
          this.size = size;
       }
    
       public ThreeDimUByteRaster generateData()
       {
          double bohrRadius = 0.53e-10;
          double factorOne = 2.0*Math.sqrt(((double)(Z*Z*Z)) / (bohrRadius*bohrRadius*bohrRadius)) / (double)n;
          double factorTwo = Math.sqrt(((double)fac(n-l-1))/(double)fac(n+l));
          int cubeSize = 201;
          ThreeDimFloatRaster floatRaster = new ThreeDimFloatRaster(cubeSize,cubeSize,cubeSize);
          double maxRaxel = 0.0;
          for (int z = 0 ; z < cubeSize ; ++z)
          {
             for (int y = 0 ; y < cubeSize ; ++y)
             {
                for (int x = 0 ; x < cubeSize ; ++x)
                {
                   double zDistance = z - (cubeSize >> 1);
                   double yDistance = y - (cubeSize >> 1);
                   double xDistance = x - (cubeSize >> 1);
                   double r = Math.sqrt(zDistance*zDistance + yDistance*yDistance + xDistance*xDistance);
                   r *= ((double)size)*bohrRadius / (double)(cubeSize>>1);
                   double theta = Math.atan(Math.sqrt(xDistance*xDistance + yDistance*yDistance)/zDistance);
                   double phi = Math.atan(yDistance / xDistance);
                   double factorThree = Math.pow(2.0*((double)Z)*r/(((double)n)*bohrRadius),l);
                   double factorFour = Math.exp(-((double)Z)*r/(((double)n)*bohrRadius));
                   double factorLaguerre = computeLaguerreFactor(n,l,2.0*((double)Z)*r/(((double)n)*bohrRadius));
                   double sHRealFactor = computeSphericalHarmonicsRealFactor(l,m,theta,phi);
                   double sHImagFactor = computeSphericalHarmonicsImaginaryFactor(l,m,theta,phi);
    
                   double realPart = factorOne*factorTwo*factorThree*factorFour*factorLaguerre*sHRealFactor;
                   double imagPart = factorOne*factorTwo*factorThree*factorFour*factorLaguerre*sHImagFactor;
    
                   double absSquare = realPart*realPart + imagPart*imagPart;
                   floatRaster.setRaxel((float)absSquare,x,y,z);
                   if(absSquare > maxRaxel) maxRaxel = absSquare;
                }
             }
          }
          ThreeDimUByteRaster uByteRaster = new ThreeDimUByteRaster(cubeSize,cubeSize,cubeSize);
          for(int i = 0 ; i < uByteRaster.getNumberOfRaxels() ; ++i)
          {
             uByteRaster.setRaxelAt(floatRaster.getRaxelAt(i) / (float)maxRaxel,i);
          }
          return uByteRaster;
       }
    
       private static double computeSphericalHarmonicsRealFactor(int l, int m, double theta, double phi)
       {
          double factor = Math.sqrt((((2.0*(double)l)+1.0)/(4.0*Math.PI)) * ((double)fac(l-m))/(double)fac(l+m));
          double realFactor = Math.cos(phi*(double)m);
          double legendreFactor = computeLegendrePolynom(l,m,Math.cos(theta));
          return factor*realFactor*legendreFactor;
       }
    
       private static double computeSphericalHarmonicsImaginaryFactor(int l, int m, double theta, double phi)
       {
          double factor = Math.sqrt((((2.0*(double)l)+1.0)/(4.0*Math.PI)) * ((double)fac(l-m))/(double)fac(l+m));
          double imaginaryFactor = Math.sin(phi*(double)m);
          double legendreFactor = computeLegendrePolynom(l,m,Math.cos(theta));
          return factor*imaginaryFactor*legendreFactor;
       }
    
       private static double computeLegendrePolynom(int l, int m, double x)
       {
          if (m > 0)
          {
             return (((double)(l-m-1))*x*computeLegendrePolynom(l,m-1,x) -
                     ((double)(l+m-1))*computeLegendrePolynom(l-1,m-1,x)) / Math.sqrt(1.0-x*x);
          }
          if (m < 0)
          {
             int sign = 1;
             for(int i = 1 ; i <= -m ; ++i) 
             {
                sign *= -1;
             }
             return sign*(((double)fac(l-m))/(double)fac(l+m))*computeLegendrePolynom(l,-m,x);
          }
          if (l > 1)
          {
             return (((double)(2*(l-1)+1))*x*computeLegendrePolynom(l-1,m,x) - 
                     ((double)((l-1)+m))*computeLegendrePolynom(l-2,m,x)) / (double)(l-m);
          }
          if (l == 1) return x;
          return 1.0;
       }
    
       private static double computeLaguerreFactor(int n, int l, double x)
       {
          double sum = 0.0;
          for (int k = 0 ; k <= n-l-1 ; ++k)
          {
             int a = n+l;
             int b = n-l-1-k;
             double aOverB = fac(a)/(fac(b)*fac(a-b));
             double sign = 1.0;
             for (int i = 0 ; i < k ; ++i)
             {
                sign *= -1.0;
             }
             sum += aOverB * sign * Math.pow(x,k) / (double)fac(k);
          }
          return sum;
       }
    
       private static long fac(long f)
       {
          long out = 1;
          for (int i = 1 ; i <= f ; ++i)
          {
             out *= i;
          }
          return out;
       }
    
    }
    

    Die Zusatzinformation ist hierbei das Zeugs, das mit @ beginnt. Wie Du siehst, braucht man relativ zum funktionalen Code da nicht sooo viel dazuschreiben, um eine bedienbare GUI zu bekommen, deshalb ist das für meine Zwecke eigentlich ganz gut. Soetwas kannst Du vermutlich nicht direkt auf C++ übertragen, Aber Ihr C++ler seid ja oft ziemlich trickreich mit eurer Sprache. Vielleicht kriegst Du ja ne Idee, wie Du etwas ähnliches realisieren könntest.

    PS: Im funktionalen Codestück da oben ist übrigens irgendwo ein Bug drin. ...und zwar in der Berechnung der Wellenfunktion für m!=0. Falls ihn einer sieht, kann er ja mal sagen, wo er ist. Ich würde mich sehr freuen.



  • Gregor schrieb:

    Aber Ihr C++ler seid ja oft ziemlich trickreich mit eurer Sprache. Vielleicht kriegst Du ja ne Idee, wie Du etwas ähnliches realisieren könntest.

    welch gehässige bemerkung. könnte glatt von mir sein.
    🙂



  • läster-freak schrieb:

    Gregor schrieb:

    Aber Ihr C++ler seid ja oft ziemlich trickreich mit eurer Sprache. Vielleicht kriegst Du ja ne Idee, wie Du etwas ähnliches realisieren könntest.

    welch gehässige bemerkung. könnte glatt von mir sein.
    🙂

    Das war durchaus positiv gemeint. 😃 Nicht, dass mich da wer falsch versteht. Ich habe schon öfter mal gesehen, dass jemand etwas mit C++ gemacht hat, von dem ich dachte, dass man es so nicht mit C++ machen könnte. Insofern wäre ich hier auch nicht überrascht, wenn jemand eine ähnliche Lösung in C++ hinkriegt. Ist vielleicht ne ganze Menge Aufwand, keine Frage. ...aber andererseits: In dem Framework, das mir die Dialoge generiert, steckt auch ne ganze Menge Aufwand drin. Java ist für soetwas auch nicht gerade ideal. ...es ist in Java machbar: Wenn man die Sprache voll und ganz ausnutzt. Ich kann C++ nicht so weit, dass ich sagen könnte, was man damit alles machen kann, wenn man die Sprache voll ausnutzt.



  • this->that schrieb:

    Der Punkt mit "unversierte Benutzer" ist Quatsch. Oder sind die Anwender von 3dsmax, maya, vs, fx composer und Photoshop unversierte Benutzer?

    Dein Punkt ist völliger Quatsch. Fällt dir nicht auf was alle von dir genannten Programme gemein haben?



  • hui, toll rege Beteiligung 🙂

    Also mit den unversierten Benutzern meine ich folgendes: kleine tools, die eigentlich nur auf der kommandozeile laufen könnten zB ein Verzeichnis als eingabe, eine datei als ausgabe. Da braucht man eig keine GUI. Wenn ich jetzt aber fürn bekannten was baue, dann kann der nicht mit kommandozeile umgehn -> daher unversierte benutzer.

    Ich meinte eigentlihc gar nicht mal so, dass das bauen des dialogs so nervig ist, sondern eher das verknüpfen von dialog mit funktionen. Die MFC benutz ich nicht mehr, da war das doch relativ einfach, das stimmt: doppelklick auf button und fertig.

    Das ist das, was mich besonders nervt, dass man alles sozusagen als ereignsroutine machen muss, und das nicht iwie automatisieren kann.

    @kommandozeilen-freak: Es geht mir hier gar nicht um große guis, sondern vl ein kleines fenster mit optionsdialog oder so. und wenn man grad keinen designer zur hand hat, muss man das halt selbst machen 🙂

    @gregor: Diese 5oder 6 zeilen mit @ machen deinen Dialog? das wär natürlich ziemlich geil, leider kann ich überhaupt kein java. KAnnst du in etwa sagen, wie du das gemacht hast? Kanns mir vl so vorstellen, dass ich ne basisklasse Dialog habe, und dem füg ich dann zB mittels AddInput(&variable, grenzen etc.) ein eingabefeld hinzu. Aber wie realisierst du in dem Fall das Layout? also dass zB zwei textfelder nebeneinader sind und anderes dann darunter etc.?

    @... Was ist ein RAD-Editor? bei google hab ich nix gefunden. Und wie meinst du kann man da mit Templates was machen? gib maln tipp bitte

    Liebe Grüße, Maxi



  • finix schrieb:

    this->that schrieb:

    Der Punkt mit "unversierte Benutzer" ist Quatsch. Oder sind die Anwender von 3dsmax, maya, vs, fx composer und Photoshop unversierte Benutzer?

    Dein Punkt ist völliger Quatsch. Fällt dir nicht auf was alle von dir genannten Programme gemein haben?

    Sie haben eine komplexe GUI und werden alle nicht von unversierten Benutzern benutzt.



  • Maxi schrieb:

    @... Was ist ein RAD-Editor? bei google hab ich nix gefunden. Und wie meinst du kann man da mit Templates was machen? gib maln tipp bitte

    Ein RAD-Editor ist ein Editor in dem du deine GUI zusammenklicken kannst. Da kannst du dann auch Events eingeben. Für wxWidgets gibt es z.B. wxSmith, welcher bei Code::Blocks dabei ist, oder wxFormBuilder als Standalone programm.

    Was Templates angeht, man kann gewisse Dinge mit Templates auslagern, in dem man sich für verschiedene Controls Klassen schreibt, die diese Wrappen. Dann benutzt man diese Klassen, statt die der Library.

    phlox





  • this->that schrieb:

    finix schrieb:

    this->that schrieb:

    Der Punkt mit "unversierte Benutzer" ist Quatsch. Oder sind die Anwender von 3dsmax, maya, vs, fx composer und Photoshop unversierte Benutzer?

    Dein Punkt ist völliger Quatsch. Fällt dir nicht auf was alle von dir genannten Programme gemein haben?

    Sie haben eine komplexe GUI und werden alle nicht von unversierten Benutzern benutzt.

    Zum Beispiel. Interessant, oder?



  • finix schrieb:

    this->that schrieb:

    finix schrieb:

    this->that schrieb:

    Der Punkt mit "unversierte Benutzer" ist Quatsch. Oder sind die Anwender von 3dsmax, maya, vs, fx composer und Photoshop unversierte Benutzer?

    Dein Punkt ist völliger Quatsch. Fällt dir nicht auf was alle von dir genannten Programme gemein haben?

    Sie haben eine komplexe GUI und werden alle nicht von unversierten Benutzern benutzt.

    Zum Beispiel. Interessant, oder?

    KA was du daran so interessant findest. Das war auf jeden Fall der Punkt, den ich zeigen wollte.



  • kommandozeilen-freak schrieb:

    zwutz schrieb:

    warum sollte die GUI auch schneller gehen? Sie ist auch mindestens genauso wichtig wie die Programmlogik.
    Die Programmlogik interessiert einen Nutzer nicht. Ihm interessiert die GUI. Und wenn ihm die nicht passt, bringt die beste Logik nichts.

    was werden denn hier für verschärfte klicki-bunti argumente gebracht?^^ 🙄
    übrigens; das bauen einer schicken GUI ist eher aufgabe eines designers, weniger die eines programmierers.
    🙂

    den Teil der GUI, den ein Designer machen sollte, hab ich mit meinem Kommentar nicht gemeint. Es geht um den Teil der GUI, um die sich ein Programmierer kümmern muss. Korrekte Tabreihenfolge, Verknüpfung mit der Programmlogik, Menüstruktur, Dialogdesign.
    Und von Klicki-Bunti hab ich auch kein Wort gesagt.

    Gutes Beispiel: Blender. Erstklassiges 3D-Modellierungsprogramm, noch dazu kostenlos. Da die GUI aber zumindest anfangs grottenschlecht war (im Sinne von unübersichtlich), haben es vor allem Neueinsteiger schwer, damit zu arbeiten.

    Eine gut durchdachte (nicht designte) GUI bringt mehr Nutzer, als eine gute Programmlogik (letztere dient dann eher dazu, die Nutzer auch zu halten). Daran sollte man vor allem denken, wenn man seine Programme auch vertreiben will



  • im grunde hat zwutz recht. einen anwender wird kaum jucken, wie ein programm intern arbeitet, solange es genau das macht, was er möchte. dem anwender ist es wurst, ob sein tool eine VB anwendung ist, die allen code in button events versteckt oder obs ne c++ anwendung ist, die sauber und elegant logik und GUI trennt.

    sauberes entwickeln macht man für sich selbst. für wartbarkeit. allerdings fällt das dann auch irgendwann wieder auf den anwender zurück, wenn der frickelcode irgendwann mehr bugs enthält, als der gut durchdachte 😉



  • Hi,

    ich kann nur sagen, daß bei dem was ich dezeit mache die eigentliche Verarbeitung eigentlich (mathematisch gesehen) trivial ist. Aber da das Programm übers Internet für möglicherweise tausende Benutzer rausgegeben werden muß, kann ich es mir nicht leisten, daß ich da groß Nutzerbetreuung machen muß. Also muß alles für möglichst JEDEN Benutzer ausreichend verständlich und selbsterklärend sowie auch zuverlässig und korrekt sein. Hab ich auch immer Probleme meinem Chef klarzumachen warum ich da so viel Schnuckebutz treiben muß, es soll doch nur ein kleines Tool werden. Aber wenn von den Nutzern jeder nur 10 Minuten Betreuungszeit braucht hab ich damit einen Fulltimejob. Also muß ich dafür sorgen, daß alle ohne mich klar kommen. Das bringts nun mal mit sich, daß die Verarbeitung nur den kleinsten Teil der ganzen Sache ausmacht. Das meiste ist Bedienerschnittstelle. Bediener sind nun mal Menschen und machen Fehler. Also muß man irgendwie daruf reagieren. Daran wird sich bei Programmen, die man aus der Hand geben muß auch nie allzuviel ändern.
    Was mir bei der ganzen Sache etwas hilft ist, daß man bei C++-Builder und Delphi (beide Borland) mit eigenen Komponenten arbeiten kann, in die man schon eine ganze Menge Selbständigkeit reinlegen kann. Wieweit das bei anderen Umgebungen geht kann ich aber nicht sagen.

    Was den Designer angeht, sicher wäre es schön einen zu haben, aber ich bin schon mal froh mich selbst zu haben. In einem Einmannteam ist man alles in einer Person. Gleichzeitig ist aber gerade die Aufgabe des Designers bei einem Programm die wichtigste von allen. Das erste Erscheinungsbild nach dem Starten und die ersten Interaktionen mit dem Nutzer entscheiden darüber ob das Programm angenommen und akzeptiert wird. Ob der Nutzer also mit SEINEM Programm arbeitet und sich dabei wohlfühlt oder nur mal nogedrungen eine Zwangsjacke anzieht.
    Für die eigentliche Funktion ist eine einladende angenehme Nutzerschnittstelle völlig unwichtig, aber der Nutzer wird einen unaufgeräumten Misthaufen nie als SEIN Programm ansehen.

    Gruß Mümmel


Anmelden zum Antworten